home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 27 / CU Amiga Magazine's Super CD-ROM 27 (1998)(EMAP Images)(GB)[!][issue 1998-10].iso / CUCD / Programming / JForth / forth.txt < prev    next >
Encoding:
Text File  |  1998-08-23  |  814.7 KB  |  10,904 lines

  1.  
  2. JForth Professional
  3.  
  4. for the Amiga
  5.  
  6.  
  7. User Manual
  8. and
  9. Reference Guide
  10.  
  11. Version 3.0
  12. January, 1992
  13. Published as freeware in 1997
  14.  
  15.  
  16.  
  17.  
  18. http://www.softsynth.com/jforth
  19.  
  20. Technical Support is not Available
  21.  
  22.  
  23. Mike Haas
  24.  
  25. Phil Burk
  26.  
  27. Brian Donovan
  28.  
  29. Jim King
  30.  
  31. with Martin Kees
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38. COPYRIGHT NOTICE AND WARNING 
  39. This software package and manual are copyrighted 1986, 1987, 1988,1989 and 1991 by Delta Research or the original author if so specified in the source code file.  
  40. This JForth package is released as freeware.  Permission is hereby given for any third party to reproduce, distribute and modify the JForth software code or any derivative works thereof without any compensation or license.  The JForth software code is provided on an "as is" basis without any warranty of any kind, including, without limitation, the implied warranties of merchantability and fitness for a particular purpose and their equivalents under the laws of any jurisdiction, as well as the provision of support of any kind.
  41.  
  42.  
  43.  
  44. How to Use This Manual   
  45. This Manual is organized into four main sections.  The first is a tutorial for people who are just learning Forth.  If you already know Forth, you may want to just skim the main tutorial until you get to the parts that are unique to JForth.  The second section describes the features of JForth as a general purpose programming language.  The third section describes the parts of JForth that are specific to the Commodore Amiga.  The fourth is an extensive glossary of the words defined in JForth and is intended as a reference.   
  46. I strongly recommend at least skimming the whole manual.  There are a lot of features of JForth that are easy to miss.  There is no point in recreating tools that already exist.  I also recommend reading the Table of Contents carefully.  I recommend also looking at the description of what files are on the disk to make sure you have not missed anything.   
  47. If you are the type of person who learns best by example, you may want to skip to the description of the demos in Chapter 3.  You can print the source code for the demos which you will find in the JD: directory on the JTools disk.   
  48. Besides this manual, you will also need a good Amiga internals manual to make use of the Amiga libraries.  The Intuition manual and the ROM Kernal manuals are particularly important.  These are available from Commodore, and most computer book stores.   
  49. Be sure to also look at the README files on the disk, and look in the JDOC: directory for any late breaking news.   Check out the Bibliography too for good Forth text books.
  50. Instant Gratification      
  51. We recommend that you read Chapter 1 first, then do the tutorials.  If you simply cannot wait then try the following steps.  If you are confused by anything, slow down and go back to the tutorial.   
  52. Step 1: Make backups of all disks.   
  53. Step 2: From the WorkBench, open the "Extras" disk then open the "Com" drawer.   
  54. Step 3: Double Click on the JForth Icon.   
  55. Step 4: Wait for JForth to load then, in JForth, enter the following paying close attention to spaces. (Note: The word ." has no spaces between the dot and the quote.)  
  56. :   HI   ."   Hello World!"  ; 
  57. HI 
  58. Congratulations.  You have just written, compiled, linked and tested your first JForth program.  JForth routines start with a colon and end with a semicolon.   
  59. Step 5: Insert the "JForth" disk and enter in JForth:  
  60. DOS EXECUTE JFORTH:ASSIGNS 
  61. Step 6: Now load the Graphics system by entering:  
  62. INCLUDE  JU:AMIGA_GRAPH 
  63. Step 7: Now open a test window and draw a line:  
  64. GR.OPENTEST
  65. 20 10 GR.MOVE
  66. 123  45  GR.DRAW 
  67. Step 8: Now close the window and get to work on the tutorials. Enter:  
  68. GR.CLOSECURW 
  69. BYE   
  70.  
  71. Acknowledgements
  72. We would like to thank the many people who have contributed to the development of JForth.  Special thanks to Martin Kees for his significant contributions to JForth 3.0, to Jack Woehr for his enthusiastic support of Forth in general, and JForth in particular, and for his valuable feedback; to Larry Polansky for his extensive support and early testing; to Marlin Schwanke for testing JForth and for hosting a JForth topic on his BBS at (619)477-2368;  to Nick Didkovsky for his help with the Debugger, ARP and his fanatacism; Bill Kelly and Kirk Baker for their contributions of public domain code and extensive testing; to Dave Sirag for his Floating Point implementation; to Bill Maginnis for his many helpful suggestions; to George Kozlowski for his version of U/ and testing; to Lynn Newton for help with the manual, and to our Beta testers - Robert Marsanyi, Curtis Stanton, Saul Lande, Mark Hellman, Chris Greene, Henry Lowengard, Jay Baldock, Robert Dickow, Rene LeBlanc, Kaspar Osterbye, Jay Christensen,  David Brown, Peter Yadlowski, Roy Brunges, Jack Johnson and others who have helped make JForth more usable for everybody.  Thanks also to the master hackers from Amiga who gave us this great machine.
  73. [Also thanks to Martin Randall for helping us with the release of JForth as Freeware.]
  74. We would also like to thank the neglected friends of us Delta Researchers for being so patient while we buried ourselves in the machine!  Sorry if we've left anybody out...it's not from lack of appreciation!
  75.  
  76.  
  77. JForth Reference Manual
  78. Table of Contents
  79.  
  80.  
  81. Forth Reference
  82.  
  83. 1) Installation and Startup
  84. Make Backup Copies    1
  85. Installing JForth on a Hard Disk    2
  86. Running JForth from Floppies using the Shell.    2
  87. Running JForth from Floppies using the Workbench    3
  88. Tips for Running With Only 512K    3
  89. Reboot    3
  90. Do NOT Load the Workbench, use the Shell    3
  91. Reduce the Size of JForth    4
  92. Running JForth with only 1 Disk Drive    4
  93.  
  94. 2) Introduction to JForth
  95. Major Functional Systems    1
  96. Grand Tour of JForth    3
  97. JForth Compared to other Forths    6
  98.  
  99. 3) JForth Disk Organization
  100. Directory Nicknames    1
  101. CL:  -  Extras:Clone  -  Clone Recompiler    1
  102. COM:  -  Extras:Com  -  Executable Command Images    1
  103. FD:  -  JForth:fd.files    2
  104. JA:  -  Extras:Appls   -   Applications    2
  105. JARP:  -  JTools:JARP  -  ARP Interface    2
  106. JD:  -  Extras:Demos    2
  107. JDEV:  -  JTools:DevTools  -  Development Tools    3
  108. JF:  -  Extras:Sysgen  -  System Generation    4
  109. JFLT:  -  Extras:Floats  -  Floating Point    5
  110. JI:  -  JForth:Include    5
  111. JIFF:  -  Extras:IFF  -  Interchange File Format    5
  112. JO:  -  Extras:ODE  -  Object Development Environment    5
  113. JPICS:  -  JTools:JPics   - Pictures for tutorials    6
  114. JRX:  -  JTools:JARexx  -  Arexx Interface    6
  115. JTX:  -  JTools:Textra_Dir  -  Text Editor    6
  116. JU:  -  JForth:Util  -  Utilities    6
  117. General Forth Utilities    6
  118. Amiga Specific Utilities    7
  119.  
  120. 4) Beginning Forth Tutorial
  121. Forth Syntax    1
  122. The Stack    1
  123. Arithmetic    4
  124. Defining a New Word    5
  125. More Arithmetic    5
  126. Arithmetic Overflow    6
  127. Character Input and Output    6
  128. Answers to Problems    8
  129.  
  130. 5) Intermediate Forth Tutorial
  131. Editing Programs in Files    1
  132. Sample Program    1
  133. INCLUDE the Program    2
  134. Variables    3
  135. Constants    4
  136. Logical Operators    5
  137. Flow of Control    6
  138. Loops    7
  139. Text I/O    9
  140. Changing Numeric Base    10
  141. Answers to Problems    11
  142.  
  143. 6) Advanced Forth Tutorial
  144. String Handling    1
  145. Saving Forth    2
  146. Programming Aids    3
  147. The Forth Interpreter and Dictionary    3
  148. Return Stack    5
  149. Extending the Compiler    6
  150.  
  151. 7) Clone - The JForth Target Compiler
  152. How To Use Clone    1
  153. Technical Information About Clone    2
  154. Clone Glossary    2
  155. Customizing the CLONEd Image    3
  156. Clone Configuration File    5
  157. Word Redefinitions under Clone    6
  158. How To Be Clone Compatible    6
  159. Differences Between Original and Cloned Code    8
  160.  
  161. 8) File I/O
  162. File I/O Tutorial    1
  163. Creating a Text File    1
  164. Reading a Text File    2
  165. Using Binary Data Files    2
  166. File I/O Reference    4
  167. Opening Files    4
  168. Reading and Writing to files.    5
  169. Closing Files.    5
  170. Building AmigaDOS Filenames.    6
  171. Sequential Virtual File Utilities    7
  172. DOLINES - Easy Text File Processing    8
  173.  
  174. 9) Floating Point Arithmetic
  175. Floating Point Tutorial    1
  176. Simple Arithmetic and Output    1
  177. Transcendental Functions    2
  178. Precision Independent Style    2
  179. Cloning Floating Point Code    2
  180. Floating Point Glossary    3
  181. Floating Point Control    3
  182. Arithmetic Operators    3
  183. Result Flags    3
  184. Transcendental Functions    4
  185. Logical Operators    5
  186. Stack Operators    5
  187. Number Storage    6
  188. Number Conversion Operators    6
  189. Display Operators    6
  190. Display Operators & Variables    6
  191. Number Interpreters    7
  192.  
  193. 10) Object-Oriented Development Environment (ODE)
  194. Philosophy    1
  195. Existing Classes in ODE    1
  196. Hidden Data    1
  197. Generic Messages    2
  198. Tradeoffs    2
  199. Origins of OOP    2
  200. Terminology    2
  201. Turorial 1 - Creating and Using Objects    3
  202. Including ODE    3
  203. Creating an Object, Instantiation    3
  204. Sending Messages    3
  205. Using Arrays    3
  206. Finding an item in an Array    4
  207. Range Checking    4
  208. Freeing Memory in Array Classes    5
  209. }STUFF: and FILL:    5
  210. Tutorial 2 - Early versus Late Binding    5
  211. To Whom It May Concern,    5
  212. Local Variables and Late Binding    6
  213. Tutorial 3 - Using OB.ELMNTS    6
  214. Predefined Classes    8
  215. OBJECT    8
  216. OB.INT - subclass of OBJECT    8
  217. OB.BARRAY - subclass of OBJECT    9
  218. Example of Using Arrays    10
  219. OB.ARRAY    10
  220. Example of Execution Array    11
  221. OB.ELMNTS    11
  222. OB.LIST    14
  223. OB.OBJLIST    14
  224. Dynamic Instantiation using OB.OBJLIST    15
  225. Defining New Classes and Methods    16
  226. Class Definition Glossary    16
  227. Instance Variables    17
  228. Using SELF in Method Definitions    17
  229. Using SUPER and SUPER-DOOPER  in Method Definitions    18
  230. Special Methods:  INIT:    19
  231. Example Class Definition    19
  232. Example of Creating a Class with Instance Objects    20
  233. Advanced Topics    21
  234. ODE Functions    21
  235. Getting Information About Classes    21
  236. Dynamically Allocated Objects    22
  237. Examining Instance Variables    22
  238. Error Reporting    23
  239. Inheritance    23
  240. Memory Placement for Amiga    23
  241. Cloning ODE Programs using JForth    23
  242. Explanation of ODE Structures Diagram    24
  243.  
  244. 11) Miscellaneous Forth Tools
  245. Memory Allocation    1
  246. Use Memory like a Stack.    2
  247. Deferred Words    3
  248. Using DEFER to "vector" code.    3
  249. Deferred System Words    3
  250. Potential Problems with Defer    4
  251. Tools for FORGET    5
  252. Local Variables    6
  253. Logging to Files or the Printer    8
  254. Word Usage Analysis    9
  255. Error Handling    9
  256. The dreaded GOTO    9
  257.  
  258. 12) System Internals
  259. USER Variable Data Area    1
  260. Data Stack Area    2
  261. Extensible Dictionary Area    2
  262. Other memory Allocation / Utilization...    4
  263. Relocations Table    5
  264. Files and Memory Housekeeping...    5
  265. JForth Compiler    5
  266. How to Generate a New JForth System    6
  267.  
  268. Development Tools
  269.  
  270. 13) Debugging
  271. Tools Overview    1
  272. Debugging Hints    2
  273. Source Level Debugger Tutorial    3
  274. Compiling with DEBUG{    3
  275. Examining Code    3
  276. Stopping with a Breakpoint    4
  277. Stopping with Control-D    5
  278. Debugging a Large Program    5
  279. Debugging a Cloned Program    5
  280. IMMEDIATE Words    6
  281. Source Level Debugger Glossary    6
  282. Debugger One Key Commands    7
  283.  
  284. 14) 68000 Assembly
  285. JForth  and 68000 Assembly Language    1
  286. JForth Register Utilization    1
  287. JForth 68000 Forth Style Assembler   (RPN)    2
  288. Motorola-Style (Forward-Parsing) Assembler    6
  289. Compiling the Forward Assembler    6
  290. The Forward Assembler Label Field    7
  291. The Forward Assembler Opcode Field    7
  292. The Forward Assembler Operand Field    8
  293. Example of Accessing Structure Members    8
  294. Example of Referencing Variables from an Interrupt    9
  295. The Forward Assembler as a MODULE    9
  296. DISM - JForth Disassembler    9
  297. Compiling the Disassembler    9
  298. Disassembler Output    10
  299. "Automatic" Disassembly Features    10
  300. Disassembling within the JForth Image    11
  301. Disassembling outside of the JForth Image    11
  302. The Disassembler as a MODULE    11
  303.  
  304. 15) Forth BLOCK Environment
  305. AmigaDOS Incompatibilities    1
  306. JForth supplied SCREEN utilities    1
  307. Line Editor Operation and Glossary    2
  308. SCRED ... the JForth SCReen EDitor    3
  309. BLOCK2TEXT    4
  310.  
  311. 16) Precompiled Modules
  312. Modules and SAVE-FORTH    1
  313. Technical Notes on Modules    1
  314. Using the Assembler and Disassembler Modules    2
  315. Using other Modules    2
  316. Files in INCLUDES Module    3
  317. Creating a Custom Module    3
  318.  
  319. 17) Miscellaneous Development Tools
  320. Command Line History    1
  321. Using the Cursor Keys    1
  322. Vocabularies    3
  323. SHOWHUNKS - for Analyzing Amiga Binary Files    5
  324. JForth Optimizing Compiler Extension    6
  325. PROFILE - Performance Analyser    7
  326.  
  327. Amiga Interface
  328.  
  329. 18) Amiga Libraries and Structures
  330. Amiga Libraries - Tutorial    1
  331. Passing Addresses to Library Routines    2
  332. Getting Values from Library Routines    2
  333. Accessing the Amiga Libraries  - Reference    3
  334. Opening Libraries    3
  335. Closing Libraries.    4
  336. Calling Amiga Libraries.    4
  337. Library Open Verification    5
  338. CALL modifiers    5
  339. CALL shortcuts    5
  340. Adding Libraries.    6
  341. Amiga 'C' Structure Interface    7
  342. Structures in the Amiga    7
  343. Loading Structure Definitions from ".j" Files    7
  344. Loading Structure Definitions from Precompiled Modules    7
  345. Using Structures    8
  346. Making an Array of Structures    8
  347. Referencing Substructures    8
  348. Accessing Array Members in Structures    9
  349. Examining Structures with DST    9
  350. Defining Your Own Structures    9
  351. Structure Glossary    10
  352. Structure Accessing Words    10
  353. Structure Defining Words    11
  354. Member UNIONs    12
  355. Addressing Considerations - Important!!!    13
  356. H2J - Convert "xx.h" to "xx.j"    14
  357.  
  358. 19) Graphics Toolkit
  359. Graphics Tutorial    1
  360. Generic Graphics Glossary    3
  361. Control Routines    3
  362. Output Primitives    4
  363. Output Attributes    5
  364. Graphics Input    6
  365. Event Driven Programming.    6
  366. Routines in JU:AMIGA_EVENTS - EV.xxxx    6
  367.  
  368. 20) EZMenu System
  369. Tutorial    1
  370. EZMenu Structure    1
  371. AMENU Program    1
  372. EZMenu Glossary    4
  373. EZMenu Default Settings    6
  374. Low Level Menu Support    6
  375.  
  376. 21) IFF Support
  377. Description of Files in JIFF:    1
  378. Tutorial 1 - Displaying Pictures    1
  379. Tutorial 2 - The Picture System    2
  380. Drawing a Portion of a Picture    2
  381. Special Effects - Wipes and Fades    3
  382. Moving a Brush, Restoring the Background    4
  383. Cleaning Up    5
  384. Picture System Reference    5
  385. Error Handling    5
  386. Double Buffering    5
  387. Using your Own Display Screen    6
  388. Clipping with Pictures    6
  389. Picture Glossary    6
  390. JIFF:PICTURE    6
  391. JIFF:PIC_EFFECTS    9
  392. JIFF:PIC_FLIP     9
  393. IFF File Support    9
  394. How JForth Handles IFF files    10
  395. Tutorial 3 - Vectored Parsing of IFF Files    10
  396. Printing Chunk Headers    10
  397. Parsing ILBM FORMs    11
  398. IFF Support Glossary    11
  399. JIFF:ILBM_PARSER    11
  400. JIFF:ILBM_MAKER    12
  401. JIFF:SHOW_IFF    13
  402. Low Level Support    14
  403. JIFF:IFF_SUPPORT    14
  404. JIFF:UNPACKING    15
  405. JIFF:PACKING    15
  406. JIFF:PACKING_OLD    16
  407. Incompatibilities with JForth V2.0    16
  408.  
  409. 22) Anims and Animbrushes
  410. ANIM Formats    1
  411. Compiling the ANIM Toolbox    2
  412. Tutorial 1 - Displaying an ANIM File    2
  413. Tutorial 2 - ANIM Control and Disk Based ANIMS    3
  414. Tutorial 3 - ANIMBRUSHES    4
  415. Animation Tips    5
  416. ANIM Support Glossary    6
  417. ANIM IFF tools    6
  418. ANIMATION Words    7
  419. ANIMBRUSH Words    8
  420. CONVERSION Words    9
  421. LOW LEVEL support words    10
  422.  
  423. 23) ARexx Support
  424. What is ARexx?    1
  425. Description of Files    1
  426. Low Level ARexx Support    2
  427. ARexx Toolbox Tutorial    2
  428. ARexx Toolbox Glossary    5
  429. Integrating Textra and JForth    7
  430. ARexx Variables Interface    8
  431. Variable Names    8
  432. The RVI Glossary    8
  433. RVI Code Examples and Test Program    9
  434. RexxView    10
  435.  
  436. 24) Miscellaneous Amiga Support
  437. What is supported and why?    1
  438. File JU:GRAPH_SUPPORT    1
  439. Font Support    3
  440. File JU:GADGET_SUPPORT    3
  441. File JU:POLYGON for Area Fill    4
  442. File JU:SCREEN_SUPPORT    4
  443. Exec Library Support    5
  444. Other Exec words - CreatePort() AbortIO() etc.    6
  445. Amiga Linked List Tools    6
  446. ANSI Text and Cursor Control    7
  447. Amiga DOS 2.0 Support    8
  448. Identifying the Workbench Version    8
  449. JU:ASL_SUPPORT    8
  450. ASL Forth Utilities    9
  451. Tag Lists    9
  452.  
  453. Glossary
  454. Key to Glossary - Stack Diagrams
  455.  
  456. Appendices
  457. A) Delta Research Biographies    1
  458.  
  459. B) Resources    2
  460. On-Line    2
  461. Organizations    2
  462. Publications    3
  463.  
  464. C) ASCII Control Characters    4
  465.  
  466. D) Sample Applications    5
  467. CR2LF.f - Carriage Return to Line Feed    5
  468. DIAL.f - Quick Dialer using a Modem    5
  469. Docu.f - Automatic "Documentation" Generator    6
  470. DumpBrush.f - Dump a brush as JForth source code.    6
  471. DumpIFF.f - Dump IFF file for analysis.    6
  472. H2J.f - Convert a 'C' style ".h" file to a ".j" file.    6
  473. Print.f - Print a File    6
  474. Rude.f - Print Rude Message using an Alert    6
  475. SortMerge.f - Merge Presorted Files    7
  476. SayNumber.f - Recite a single-precision number in decimal    7
  477. Terminal.f - Very Dumb Terminal Program    7
  478. Update.f - Copy newer files from one directory to another    7
  479. WordCount.f - Count Words Lines and Chars    7
  480.  
  481. E) Style Guidelines    8
  482. Naming Conventions    8
  483. Transportability Techniques    10
  484. Multistandards    12
  485.  
  486. F) Words by Function    13
  487.  
  488. G) Incompatibilities    18
  489. Between V2.0 and V3.0    18
  490. Error Handling in IFF and Picture words.    18
  491. Local Variables    18
  492. Between V1.2 and V2.0    18
  493. >BODY and BODY>    18
  494. CONSOLE    19
  495. Totally New Floating Point    19
  496. Bugs Fixed    19
  497. Signed AND Unsigned Structure Members    19
  498.  
  499. H) Products Written in JForth    20
  500. B.A.D. from MV Micros    20
  501. My Diary from MV Micros    20
  502. HMSL, the Hierarchical Music Specification Language    20
  503. Copyist Companion by Nick Didkovsky    20
  504. Doctor Nerve with Nick Didkovsky    21
  505. IntuiEZ by Curtis Stanton    21
  506. XL by Martin Kees    21
  507. JGoodies_1 from various.    21
  508.  
  509. TC -      Table of Contents
  510.  
  511.     Table of Contents    TC -  
  512.  
  513.  
  514. Chapter 1
  515. Installation and Startup
  516. [Note: These instructions were for the commercial version of JForth.  Please refer to the instructions that came with the Freeware archive for the latest information.]
  517. Prerequisites
  518. For the optimal use of JForth we recommend having at least 1 Megabyte of memory and either two floppy drives, or one floppy and a hard drive.  It is possible to use some parts of JForth with only 512K of RAM or one disk drive, but limitations are quickly encountered.  We will describe later in this chapter how to do that.
  519. We also recommend that you be familiar with the general use of the Amiga and the AmigaDOS operating system.  Specifically, you should be familiar with performing the following tasks:
  520. 1) Making backup copies of floppy disks,
  521. 2) Opening a CLI or Shell window,
  522. 3) Using the CLI commands ASSIGN, COPY, DIR, EXECUTE, RENAME and RUN.
  523. If you are not familiar with these, please review the Amiga User Manual and other documentation because an explanation of these is beyond the scope of this manual.   You should be comfortable with the operation of the Amiga before attempting any programming.  Once you are familiar with Amiga operation, the use of JForth should be quite straight forward.
  524. We recommend that you work from a CLI window or a Shell window.  You can also work from the Workbench but this is a less powerful environment for programming. 
  525. To open a Shell window in Amiga DOS, open the Workbench or your hard disk icon and double click on the "Shell" icon.
  526. Make Backup Copies
  527. JForth Professional comes on three disks.  The "Extras" disk and the "JTools" disk are specifically labeled as such; the remaining disk is simply called "JForth".
  528. The first thing is to make working copies of your disks.  You should then keep the original copies as backups.  JForth is not copy protected so you can use DISKCOPY from the CLI. If you use the Workbench to make your copies, you will need to relabel the new disks because the Workbench prepends "Copy of" to the disk label.  Remove that so that the copies have the same names as the originals.  It is probably a good idea to write protect your original disks before starting to make the backups to avoid accidental erasure.
  529. It is also very important to frequently make backup copies of the programs you write.  Making backups is important even if you are the kind of person who never makes mistakes.  If the power goes out, or some other error occurs, while you are writing to a disk, then you will probably lose at least one file.  It is usually the file you are working on.  As long as you make frequent backups of your work, you can minimize your loss. 
  530. The steps you take now depend on the configuration of your Amiga system.
  531. If you have a Hard Disk, proceed with the section on Hard Disk Installation.
  532. If you only have One Floppy Disk Drive and NO hard disk, skip to the section on running with 1 drive, (or buy another disk drive).
  533. If you have two floppy disk drives and at least 1 Meg of RAM, skip to the section on running JForth from Floppies.
  534. Installing JForth on a Hard Disk  
  535. We have provided a script file to help users install JForth on a hard drive.  It will create a directory called WORK:JFORTH_DIR on your hard disk.  It will then copy the three JForth disks into separate directories in the new directory.  If you would like to specify a different name for this directory, you can pass a directory name as a parameter to the script.
  536. Note: If you have a previous version of JForth installed, you will need to UN-ASSIGN the JFORTH:, and EXTRAS: logical volumes.  Otherwise the system will confuse the JFORTH: on your hard disk with the JFORTH: floppy disk.  The best way to UN-ASSIGN these is to remove the ASSIGNs in your startup sequence in the S: directory, then reboot the Amiga.  You do not need to remove the old version itself but you may want to rename the directory it is in to avoid naming conflicts with the new version.
  537. To install JForth on a hard disk, put the JTOOLS: disk in a floppy drive then enter in the shell:
  538. CD RAM:
  539. COPY JTOOLS:INSTALL_JFORTH RAM:
  540. You now have a choice to make.  To put JForth in the directory WORK:JFORTH_DIR, enter:
  541. EXECUTE INSTALL_JFORTH
  542. or, to use a different, directory, enter:
  543. EXECUTE INSTALL_JFORTH other_directory_name
  544. You will then be asked to insert the three JForth disks, one at a time.  It will take several minutes for the files to copy.
  545. You should now modify your startup sequence based on the instructions printed when the script finishes.  These modifications will assign logical names to the JForth directories so that JForth will know where to look for its files.
  546. Finally reboot the computer so that the ASSIGNs will be executed.  To run JForth you can now enter:
  547. RUN COM:JFORTH
  548. If you would like to perform a quick test of JForth, wait for JForth to start, then enter in JForth:
  549. INCLUDE JD:DEMO_BOXES
  550. After compilation is complete, enter:
  551. BOXES
  552. You should now see a window with random boxes being drawn.  Click in the closebox (upper-left) to stop the demo.
  553. To quit from JForth, enter:
  554. BYE
  555. Running JForth from Floppies using the Shell.
  556. Put your working copy of the "JForth" disk in the external drive and enter:
  557. EXECUTE JForth:ASSIGNS
  558. This sets up logical volumes in the Amiga that will help it keep track of where files are located.  Put your JTools disk in the external drive and enter:
  559. EXECUTE JTools:ASSIGNS
  560. Now put your working copy of the "Extras" disk in the external drive and enter:
  561. EXECUTE Extras:ASSIGNS
  562. Now, let's run JForth itself. Enter:  
  563. RUN COM:JFORTH
  564. This will load JForth.  You will eventually see a new window pop up that has the Delta Research copyright.  If you hit a carriage return, you will see an OK message appear.  This is your sign that JForth is working.   
  565. You can now move on to the tutorials.  When you are eventually ready to leave JForth, enter:  
  566. BYE
  567. This will close the JForth window and terminate execution of JForth.
  568. Running JForth from Floppies using the Workbench
  569. Insert your "JForth" disk in any drive.  Double click on the disk icon to open it.  Now double click on the "Assignments" icon.  This will run the ASSIGNS command file.
  570. Repeat the above procedure for the "JTools" and "Extras" disks.
  571. Now open the COM drawer on the Extras disk and double click on the JForth icon.
  572. This will load JForth.  You will eventually see a new window pop up that has the Delta Research copyright.  If you hit a carriage return, you will see an OK message appear.  This is your sign that JForth is working.   
  573. You can now move on to the tutorials.  When you are eventually ready to leave JForth, enter:  
  574. BYE
  575. This will close the JForth window and terminate execution of JForth.
  576. Tips for Running With Only 512K   
  577. We recommend having at least 1 Megabyte of memory.  The operation of the Amiga is greatly improved by the addition of extra memory.  You can use recoverable RAM disks and add extra disk buffers to speed up disk access. With enough memory and AmigaDOS 1.3 you can even reboot from RAM.   
  578. If you have an Amiga with 512K of RAM you will be able to run JForth but will not have much memory to spare.  To give yourself room for JForth AND a text editor you may have to take some steps to reduce your memory consumption.  Here is a list of some things you can do to give yourself more room.  You probably do not need to do all of these things.  Just pick what you want to try.   
  579. Reboot
  580. If you have been running your Amiga awhile, your memory can become fragmented.  This is not as bad as it sounds.  It just means that the free memory in your system is arranged in many small pieces instead of a few large pieces.  JForth needs a large piece to fit in.  By rebooting, you can reorganize the free memory on your system into larger pieces.  I recommend getting a copy of the program AVAIL which will tell you how much memory you have and how big the largest piece is.   
  581. Rebooting will also clear out any fonts or libraries that other programs opened and left laying around in memory.
  582. Before rebooting first make sure that all your applications have stopped because anything in RAM will be lost.  To reboot, hold down the <CTRL> key and the two <AMIGA> keys simultaneously.
  583. Do NOT Load the Workbench, use the Shell  
  584. Another way to save memory, about 13K, is to give up using icons.  You can prevent Workbench from loading by modifying your startup sequence to open a Shell instead of the Workbench. 
  585. Edit the file S:STARTUP-SEQUENCE.  Change the following text at the end of the file:  
  586. LOADWB 
  587. to be:  
  588. ; LOADWB
  589. NEWSHELL
  590. Adding a semicolon will comment out a line.   
  591. Reduce the Size of JForth  
  592. The original JForth comes with 64K of free dictionary.  If you don't need this much you can reduce the size of your JForth image by changing #K and using SAVE-FORTH.  Use a BACKUP copy of JForth for this exercise.  Enter in the CLI:  
  593. EXECUTE EXTRAS:ASSIGNS
  594. RUN COM:JFORTH 
  595. Now enter in JForth:  
  596. #K @ .  \ print how much
  597. #K @ 20 - #K !  \ subtract 20K 
  598. SAVE-FORTH COM:JForth 
  599. BYE 
  600. Now enter in the CLI:  
  601. RUN COM:JFORTH 
  602. The new image will use about 20K less memory.  Some large programs may not load in this smaller dictionary space.  Please see SAVE-FORTH in the glossary for more information about this technique.   
  603. Running JForth with only 1 Disk Drive 
  604. The Amiga operates best with 2 floppy disk drives or 1 floppy and a hard disk.  Cost is a limiting factor for many people, however, so we have made provisions for running from 1 drive.   
  605. The most important thing to do when running from 1 drive is to limit the number of disk swaps you have to make.  The Amiga will ask for the Workbench disk when it needs to load a command from the C: directory.  You can avoid many of the requests for the Workbench disk by placing the necessary commands in RAM.  The Amiga will be able to load these commands from RAM and not need the Workbench disk as often.  (Please note that since these commands will take up RAM space so you might have problems if you only have 512K of memory.)  
  606. The commands that should be in RAM:, or made RESIDENT, are CD, DIR, RUN, EXECUTE, ASSIGN, LIST and COPY.
  607. 1 -      Installation and Startup
  608.  
  609.     Installation and Startup    1 -  
  610.  
  611.  
  612.  
  613.  
  614. Chapter 2
  615. Introduction to JForth     
  616. JForth is a programming language that allows you to interact with your Amiga.  When you are programming in JForth, you are "inside" the language. You can access any data structure, test any routine, or use any development tool, right from the keyboard.  This direct communication with the computer can improve your productivity, giving you additional time to improve the quality of your software products.   
  617. JForth is based on the 1983 standard Forth language.  Forth was first conceived by Charles Moore when he wanted a new language for controlling telescopes.  He developed a language based on a dictionary of words.  This dictionary can be extended by writing new words based on the old ones. Since Mr. Moore's original version, Forth has been translated to almost every type of computer from the biggest mainframes to the smallest microcomputers.
  618. Since a minimal Forth can be implemented in just a few kilobytes of memory, it is often used in very small embedded computer systems for process control and robotics.  Forth, however, is equally appropriate for larger, more advanced, computers like the Amiga.  Forth is a very flexible language and can be adapted to larger computers without losing the flavor of the original language. 
  619. JForth is an implementation of Forth designed specifically for the Commodore Amiga.  JForth uses a 32-bit stack and compiles directly to 68000 machine code.  This makes JForth faster than most Forths.  JForth also provides an extensive set of tools for accessing the special features of the Amiga.  You can call any Amiga Library routine by name and reference any Amiga structure using constructs similar to 'C'.  JForth also has some special toolboxes that support simple graphics, Intuition menus, IFF files, and other Amiga features.  These toolboxes can be used directly to simplify your Amiga programming.  Source code for all these toolboxes is provided so you can customize them if needed or study them as examples of Amiga programming.  JForth also provides over a dozen small sample programs for those, like me, who learn best by example.  
  620. JForth also allows you to do things that are unique in the Forth experience, the most dramatic being CLONE.  This exeptional utility allows you to create a totally independant, standalone version of your program of minimal size that is entirely royalty free! 
  621. Major Functional Systems    
  622. For a full list of the tools that JForth offers, you should read the next chapter about the various files on the disks.  The systems mentioned here are ones that we feel are major ones not to be missed. 
  623. Amiga Library Calls  
  624. JForth provides a system for easily calling any Amiga Library routine by name.  It will figure out what 68000 registers the parameters go into and build the appropriate code.  Thus you can simply pass parameters on the stack in the order described in the Amiga documentation.  A number of toolboxes have been written for supporting specific parts of the Amiga Library including EZMENUS, Graphics, the Serial Device, ANSI codes, and much more.   Chapter 18 covers the details of Amiga library access.
  625. Amiga Structure Support  
  626. JForth provides the equivalent to all of the ".h" include files from 'C'. These ".j" files define all of the necessary structures and constants for passing information to the Amiga Library routines.  Structures can be dumped interactively with all members shown by name and value for debugging by using DST.  Chapter 18 further discusses this helpful feature.  
  627. ARexx Support
  628. ARexx is a language that helps various applications communicate with each other.  A spread sheet program, for example, could communicate with a data base program.  These tools help you write ARexx compatible programs.  Chapter 23 further discusses AREXX.  
  629. Assembler
  630. JForth support two 68000 assemblers, one with Reverse Polish Notation (RPN) and one with Motorola like syntax.  The RPN assembler can be used to create macros but the Motorola assembler is easier to read.  We also offer a Disassembler.   All are covered in depth in Chapter 14.
  631. Block Support and SCRED  
  632. For those who prefer the old fashioned BLOCK or SCREEN environment, we provide LIST, LOAD and the standard line editor.  We also provide a WYSIWYG SCREEN editor called SCRED.  (We recommend the use of normal text files with JForth).  Chapter 15 discusses the BLOCK environment.   
  633. Clone  
  634. Clone can be used to generate small, royalty free, executable images of your JForth programs.  Clone will take a compiled JForth program, extract out all of the code and data needed to run it, and reassemble a smaller version of it.  All of the JForth development tools, the name fields and link fields and any other unused words are left behind.  The final image size is comparable to images created using a 'C' compiler and linker. Images can be saved with a symbol table for use with WACK or other debuggers (if needed).  The JForth Source Level Debugger can also be used with Cloned programs.  Most programs will Clone without modification if they follow a few simple rules regarding run time initialization of variables or arrays containing Forth addresses.  See Chapter 7 for further information.
  635. Debugger  
  636. JForth provides a source level debugger that allows you to single step through your code.  At every step you can see what is on the stack.  You can also examine the return stack, dump memory, set breakpoints, control execution, or even enter Forth commands.  Chapter 13 fully documents the source level debugger.
  637. Floating Point  
  638. JForth support both the single precision Fast Floating Point and the IEEE double precision.  These words conform to the Forth Vendors Group Standard.  Chapter 9 describes the Floating Point implementation.
  639. IFF Support  
  640. JForth provides general purpose tools for reading and writing IFF files. It also provides a toolbox specifically for ILBM graphics files.  This allows you to use pictures, brushes, anims and animbrushes from a paint program, or other source, in your programs.  JForth also provides tools for animation and presentation such as, blit, wipe, fade in, fade out, etc.  Powerful graphics and animation programs can be created using these tools.  Chapter 21 will further guide you in this area.
  641. Local Variables  
  642. Local variables can simplify the definition of complex words by eliminating much of the stack manipulation.  Local variables are fast self fetching variables that allow reentrant recursive code to be written.  Using regular VARIABLEs can make a word non reentrant.  Local variables are specifically covered in Chapter 11.
  643. Modules
  644. JForth's precompiled modules provide a method for rapidly accessing code that is used during complation.  This includes the Assemblers and Disassembler, and the Amiga include files.  These modules are dynamically linked into the dictionary when needed.  This way, they do not take up space in your normal dictionary, yet are instantly available.  See Chapter 16 for more information about modules.
  645. MultiStandard  
  646. This system allows you to switch easily between JForth and the major standards - FIG , '79 , and '83.  This is handy for compiling code written using other Forths.  Multistandard is discussed in Chapter 17.
  647. ODE  
  648. ODE is an Object Oriented Development Environment similar in concept to SmallTalk.  It allows you to define classes of intelligent data structures, then create as many copies of these data structures as needed.  This technique can simplify programming immensely by making it easier to write reusable code.  Chapter 10 is devoted to ODE.
  649. Profiler
  650. This optimization tool monitors the operation of a program to find out where it is spending its time.  Most programs spend most of their time in a small portion of the code By identifying this code, one can focus efforts at optimization where they are most needed.  The profiler is documented in Chapter 17.
  651. Textra
  652. Textra is a powerful, yet easy to use, multi-window text editor designed for programmers.  It uses the mouse to select text and allows Cut, Copy and Paste, operations between its windows.  It also incorporates ARexx hooks that allows you to use provided macros (.textra files) for text processing (or write your own).  Textra can communicate with JForth such that you can compile directly from the editor. If an error is encountered while compiling, Textra will highlight the error so the you can fix it quickly.  The documentation for Textra may be found in the JTX:DOCS directory.  To access the '.textra' REXX scripts enter:
  653. COPY JRX:SCRIPTS/#? REXX:
  654. Grand Tour of JForth    
  655. The section describes some of the special features of JForth.  If you have never used any Forth, you may want to try the tutorials first.  Then come back to this chapter because it describes features you should know about.
  656. JForth has so many tools and utilities that it is easy to miss something useful.  We recommend studying this manual carefully so that you can take advantage of all that JForth has to offer.  You should also read some of the source code files where you may find some undocumented goodies.   
  657. Let's start with a grand tour of the main JForth tools.  Bring up JForth and try out these commands as we discuss them.  (If you are unclear about how to read stack diagrams, please try the tutorial first.)  
  658. WORDS ( -- , list the words currently available )  
  659. This command lists the words in the dictionary that you can call.  Although thousands of words may be listed, you will only need to learn a few.  You can stop the output of this list by hitting a key.  Hit return to continue listing or enter "quit" to stop.  You could also enter a Forth command while WORDS is paused.  This pause feature is provided by ?PAUSE which is described in the glossary.  VLIST is a synonym for WORDS.   
  660. WORDS-LIKE ( <word-fragment> -- , list all with fragment )  
  661. Use this if you want to see all of the words that have some word fragment in their name.  Enter:  
  662. WORDS-LIKE  EMIT  ( all words with EMIT ) 
  663. WORDS-LIKE  +     ( all words with '+' ) 
  664. As a shortcut, if you hit <Function-Key-6> it will insert WORDS-LIKE into your input stream.  This will save you from having to type it in.  Hit the <HELP> key to find out about other function key assignments.  Now hit the <Up-Arrow> key repeatedly to scroll through your previous commands just like in the Amiga DOS shell.  You can look in the section on Command Line History for more information about this.   
  665. FILE? ( <name> -- , show file and source code )  
  666. If you are curious about how a word is defined you can use FILE? to see what file it is from.  It will then ask you if you want to see everywhere it is referenced or defined in that file.  This will work for every word in JForth except those from the Assembly Language Kernal which is proprietary. (Hey! We gotta have some secrets!)  
  667. FILE? ANEW 
  668. EACH.FILE?  ( <name> -- , show every file and source code )  
  669. If a word has been redefined, this command will find every occurrence of it in the dictionary and show it to you.   
  670. EACH.FILE?  AUTO.INIT 
  671. EACH.FILE?  [FORGET] 
  672. DEF  ( <name> -- , disassemble word )  
  673. Here is a handy word for those of you who are familiar with 68000 assembly language.  DEF will disassemble any Forth word.  (See the chapter on the 68000 assemblers for more info.)  
  674. DEF 1+ 
  675. DEF CMOVE 
  676. The first time you enter DEF it will load a precompiled MODULE containing the disassembler.  This gives you quick access to DEF without taking up room in the dictionary or having to compile it yourself.   
  677. DOS  ( <command-line> -- , pass command to Amiga DOS )  
  678. You can execute almost any Amiga DOS command line except those that require input, and CD.  For CD, just enter CD without using the DOS keyword (CD has been provided for you in the JForth dictionary).  Some common DOS commands have been predefined.  (See the file JF:DOSCOMMANDS for more information.)  
  679. Execute arbitrary DOS command 
  680. DOS TYPE S:STARTUP-SEQUENCE OPT H 
  681. For CD, use CD directly.  
  682. CD RAM: 
  683. Use predefined command.  
  684. DIR DF0: 
  685. Pass command in string.  
  686. " RENAME RAM:MOO RAM:GOO"  $DOS
  687. MEASURE ( <Forth-line> -- , time Forth commands )  
  688. This is handy when you are trying to speed up your code.  This command will tell you how long things take.  It will take the commands that follow, execute them and tell you how long it took.   
  689. MEASURE DIR 
  690. BENCH  ( <Forth-line> -- , time commands with overhead )  
  691. MEASURE and BENCH are only accurate to about 1/50th of a second.  If something takes less than 1/2 a second you should call it N times in a loop then divide by N to find out the actual time.  If you want to take the loop overhead into account, use BENCH and BENCH.WITH.   
  692. : TDO  ( N -- ) 
  693.     0 DO LOOP 
  694. : TSWAP ( a b count -- a b | b a ) 
  695.     0 DO SWAP LOOP 
  696. 1,000,000 BENCH.WITH TDO 
  697. 11 22 33 1,000,000 BENCH TSWAP 
  698. INCLUDE ( <filename> -- , compile source code from a file)  
  699. You can specify a complete pathname or use the current directory.  INCLUDE can be nested so you can call INCLUDE in the file you are currently INCLUDEing.  (See INCLUDE? in the glossary.) INCLUDE is a very important word so we have assigned it to <Function-Key-1>.   
  700. INCLUDE JU:RANDOM 
  701. 6 CHOOSE .  ( random number, 0 <= R < 5 ) 
  702. 6 CHOOSE .  
  703.  
  704. TYPEFILE JU:LOGTO 
  705. MEASURE INCLUDE JU:LOGTO 
  706. JForth uses a HASHED dictionary to speed up compilation.  This is a special way of looking words up directly instead of scanning the entire dictionary. If we turn off hashing we can see how hashing speeds up the compile process...   
  707. HASH.OFF 
  708. MEASURE INCLUDE JU:LOGTO
  709. Notice the difference in compile speed.  Hashing does not, however, come without a price.  JForth has to build a table of pointers for hashing to work. This rehashing is required whenever you FORGET code or do a GETMODULEs.  If we recompile LOGTO with hashing on we will have to rehash.   
  710. HASH.ON 
  711. MEASURE INCLUDE JU:LOGTO
  712. This is still faster than compiling with hashing off.  Hashing is most effective with large files when the dictionary has lots of words already defined.  Some people have reported an 8-9 times speed up.  Hashing is least effective when you recompile small files but they are pretty fast anyway. Hashing will speed up compilation in almost every instance so we usually leave it on.   
  713. MAP ( -- , display system status )  
  714. This word tells you all about the current system, how many files are open, how much room is left in the dictionary, etc.  This is assigned to a function key.  Hit <HELP> to find out which one.   
  715. SAVE-FORTH  ( <filename> -- , save current JForth system )  
  716. If you compile some code and want to save the dictionary in its current state, use SAVE-FORTH to write it to a file.  You can run this image later, just like you did COM:JForth.  If you try this you should write it to a work disk (NEVER write to the original JForth disks).  If you want the new image to have more dictionary space available, increase the value of the variable #K before you SAVE-FORTH...
  717. #K @ .   ( see how much is there ) 
  718. 50 #K +! ( increase it by whatever you think you need ) 
  719. SAVE-FORTH  WORK:MY4TH 
  720. Be mindful that when you SAVE-FORTH, any opened files or allocated memory will not be preserved in the saved-image, so your programs should re-establish such resources in an INIT-type word.  Unless your program meticulously cleans-up after itself, you should SAVE-FORTH after immediately compiling and before running it so that you save a pristine image.  See the glossary for more information.     
  721. JForth Compared to other Forths   
  722. This section describes some of the ways in which JForth differs from other Forths.   
  723. 32 Bit Stack  
  724. Forth uses what is called a "data stack" for passing values between words. It is a place to put numbers, addresses or other values.  Values can be added to the stack and removed just like on a stack of plates.  Most Forth implementations use a 16 bit stack.  This means that the numeric range in a standard Forth is -32,768 to 32,767.  JForth and a few other Forths, use a 32 bit stack which gives you a numeric range of -2,147,483,648 to 2,147,483,647.  Since JForth addresses are also 32 bit, you can address a much larger memory space than a 16 bit Forth.   
  725. Jump Subroutine Threading  
  726. Another major difference between JForth and most other Forths is that JForth is a true compiler.  In most Forths,when you "compile" a word, you actually end up creating a table of tokens or pointers to the other words that are called.  If your word calls '+' it will put a pointer to the plus function in your word.  When you execute your word, a program called the inner interpreter examines these pointers and then executes the appropriate functions That is the traditional method.   
  727. In JForth we use what is called Jump Subroutine, or JSR, Threading.  That is where the 'J' in JForth comes from.  In JSR threading, actual 68000 machine code is compiled into your word.  If you call a word, JForth will compile a 68000 JSR instruction to make that call.  This eliminates the need for an inner interpreter.  If the subroutine is small enough, JForth will copy the called routine inline into your routine thus avoiding the small overhead of the JSR instruction.  Since the 68000 executes code directly, JForth will run 2-3 times faster than a traditional Forth on the same machine.   
  728. Relative Addressing  
  729. In JForth, addresses are expressed as offsets relative to the base of the JForth image in memory.  This is important because AmigaDOS will load JForth at different places in memory at different times.  Despite this, your programs can use the same relative addresses at different times.  This can simplify Forth programming because variables, CFAs, dictionary links, and other addresses keep the same relative addresses even thought their absolute addresses may change.   
  730. Amiga Libraries uses absolute addresses.  You will, therefore,  have to convert relative addresses to absolute before passing them to the Amiga. This is a simple operation.  On the whole, we feel using relative addressing is an advantage over absolute addressing.   
  731. Here are the words used to convert addresses:  
  732. >REL  ( absolute-address -- relative-address , convert )  
  733. >ABS  ( relative-address -- absolute-address , convert )  
  734. (Also remember that the addresses on the return stack will be absolute as well.  We have provided words for accessing "inline" data based on reading the return stack.  Please see the appendix on Transportability.)  
  735. Text File Input  
  736. JForth will compile programs from "normal" ASCII text files created using standard Amiga text editors.  Thus you can use you favorite editor with JForth instead of the TEXTRA editor provided.  (Traditional Forths use a system of 1024 byte source code blocks. We provide support for this system for those who want it.)  
  737. NOT versus 0=  
  738. In the Forth '83 standard, NOT performs a 1's complement operation.  Since NOT is usually used for negating a logical value, this can sometimes give surprising results.  In Forth, any non zero value will be considered true by IF and other conditional words.  The traditional NOT only works with a true value of -1.  For that reason, JForth defines NOT as 0= which negates any true value.   
  739. In Forth '83 
  740.         -1 NOT ( is false ) 
  741.          1 NOT ( is true!!, = -2 ) 
  742.          1 0=  ( is false ) 
  743.  
  744. In JForth 
  745.         -1 NOT ( is false ) 
  746.          1 NOT ( is false ) 
  747.          1 0=  ( is false ) 
  748. The JForth word COMP will perform a 1's complement operation like the '83 NOT.  If you want the traditional NOT you can redefine it or use the Multistandard package which gives you strict conformance with '83, FIG or '79 standards.   
  749. Floored Division  
  750. JForth division is not floored.  This means that the results of a division are rounded up if they are negative.  In floored division the result is rounded toward negative infinity.   
  751. In JForth:   -13 2 / .  ( gives -6 ) 
  752. Floored:     -13 2 / .  ( gives -7 )
  753.  
  754. 2 -      Introduction
  755.  
  756.     Introduction    2 -  
  757.  
  758.  
  759.  
  760.  
  761.  
  762.  
  763. Chapter 3
  764. JForth Disk Organization   
  765. JForth is released on three disks named JForth, Extras and JTools  [The Freeware version is released in a single archive.]
  766. Each disk contains several directories, each containing a specific set of related files.   Only four of the directories do not contain JForth program source files; COM: holds only executable binary images, FD: stores information used by the JForth compiler to interface with the Amiga ROM Kernel, and MOD: holds precompiled code.   
  767. Directory Nicknames
  768. JForth utilizes features provided by the AmigaDOS ASSIGN command to create nicknames for each of the normal directory pathnames.  By executeing (another AmigaDOS command) the assigns file that is on the root of each disks, you can teach your system these nicknames.  This need only be done once per session, when you first insert the disks in your system.  If you install JForth on your hard disk as described in chapter one, then these assigns will be done automatically.
  769. There are a number of benefits to using assigned names:
  770. 1) They short and require less typing then the full path names.
  771. 2) You can always use the same name regardless of the actual pathname of the directory.  You can always reference JU:LOCALS with the same name regardless of whether JU: is JForth:Util or WORK:Programming/JForth_Dir/JForth/Util.
  772. Please read about ASSIGN in the Amiga DOS manual if you are not familiar with this very powerful command.
  773. If you enter an assigned name and Amiga DOS asks you to enter a disk with the logical name, then your assigns are not set properly.  Check the installation procedure to make sure you have executed the assigns properly.  If you are not using a hard disk you can simply enter:
  774. EXECUTE JFORTH:ASSIGNS 
  775. EXECUTE EXTRAS:ASSIGNS 
  776. EXECUTE JTOOLS:ASSIGNS 
  777. Once this has been done, JForth will be able to locate all required source files.
  778. The following is a description of each JForth directory in alphabetical order.  Be sure to read the description of JU: since it contains the most generally useful utilities.
  779. CL:  -  Extras:Clone  -  Clone Recompiler
  780. CLONE is compiled by loading CL:TOPFILE.  Clone is used to generate stand-alone royalty free applications.
  781. COM:  -  Extras:Com  -  Executable Command Images
  782. JKERNAL - This image is the basic Forth engine and primitives.  Once executed from AmigaDOS, files from the 'JF:' (Extras:SysGen) directory are INCLUDEd to generate a new, fully-operational, JForth image.  Since a completely compiled development image is supplied (see 'JForth', below), this need only be done if the files in the 'JF:' directory have been altered by the programmer.   
  783. * JFORTH -  This is the main JForth executable image.  This file is comprised of the kernel image (described above) and utilities compiled from the JF:' directory, notably the disassembler, timing words, a pattern-matching 'VLIST', Hashing, History and others.  See the chapter on "System Internals" for more information on recompiling COM:JForth.
  784. FD:  -  JForth:fd.files     
  785. This directory contains all the information that the JForth compiler needs to create the proper glue routines to interface to any and all Amiga library calls.  As supplied, the files in this directory describe the 2.0 version of the AmigaDOS operating system.   
  786. JA:  -  Extras:Appls   -   Applications
  787. We have provided several complete applications written in JForth.  They can be used either directly from JForth or they can be cloned and used as CLI commands.  Some of them demonstrate how to parse the command line, how to handle input errors and printing "help" information.  The file names all end with ".f" to distinguish the Forth source file from the cloned image file.   
  788. These are described in more detail in an appendix.  Please see the chapter on Clone for instructions on how to clone these applications.   
  789.  
  790. JARP:  -  JTools:JARP  -  ARP Interface
  791. ARP stands for Amiga DOS Replacement.  It is a popular library of calls
  792. ARP.J   - Include file for interfacing to ARP library.
  793. ARPFileRequest.f   - Simple call to ARP's file requester.
  794. JD:  -  Extras:Demos     
  795. This directory contains the JForth source code for all of the supplied demo programs.  You can include each demo individually or include most of them at once by INCLUDEing JD:LOAD_DEMOS. At the end of the compile, instructions on how to execute the demos is printed.   
  796. These demos illustrate how to use various aspects of the JForth programming environment and the Amiga.  You may find these useful as a starting point for your own programs.  Feel free to modify these demos and include parts of them in your commercial products.   
  797. BENCH_PRIMITIVES   - benchmark programs for primitive operations.  Use this to compare JForth with other Forths.
  798. DEMO_BOXES  -  This program is similar to the BOXES demo that comes with the Amiga.  It shows you how to open a window and draw random rectangles.  It also illustrates using the XOR mode of drawing, and changing colors.   
  799. DEMO_CLICK  -  Shows how to detect double clicks.
  800. DEMO_CIRCSQ   - Graphical pattern generator using algebraic functions.
  801. DEMO_DBUF   - Shows how to create a double buffered video display.
  802. DEMO_DOTS   - Simple random pixels.
  803. DEMO_FONTS  -  Shows how to open and use Amiga fonts.
  804. DEMO_GADGET  -  Shows how to use most of the gadget types available in a simple "do-nothing" program.
  805. DEMO_GSORT  -  An animated demonstration of using the Batcher's sort.  It generates random length rows and sorts them visually.   
  806. DEMO_HAM  -  This illustrates opening a CUSTOM SCREEN in HAM mode.  A BACKDROP window is then opened within it and some random 'art' is generated.   
  807. DEMO_INTERRUPT  -  Shows how to install an interrupt handler.  Uses the Vertical Blanking Interrupt to generate a 60 hertz clock.  See also HIGH_INTERRUPT which shows a way to call high level Forth code from an interrupt (not recommended).
  808. DEMO_LINES  -  This is similar to the LINES demo from Commodore, except it stays within the window.  It generates sweeping line patterns in different colors.   
  809. DEMO_MENUS  -  The use of the EZMENU system is shown here.  A set of menus that demonstrate mutual exclusion, checking,  setting of command keys, etc. is built and used.   
  810. DEMO_MSG  -  Open a message port and send a message.
  811. DEMO_PAINT  -  This is a simple paint program that demonstrates the use of graphics input events.  A call to EV.GETCLASS is made.  The colors are cycled automatically.  Detects and responds to double clicks.
  812. DEMO_POLYGON  -  Use the AREADRAW routines to draw polygons.
  813. DEMO_RAIN  -  This doesn't teach anything that BOXES doesn't already show but it looks interesting so here it is.
  814. DEMO_RAWKEY   - Shows how to get RAWKEY events from a window and convert them.
  815. DEMO_RGB  -  Cycle colors by changing the color map of a screen.
  816. DEMO_SCROLL  -  The demo shows you how to make a direct call to an Amiga graphics library routine, ScrollRaster.  It also uses line drawing.   
  817. DEMO_SPEAK  -  This small demo illustrates the use of the Amiga Translator library and Narrator device to create a synthetic dialog.  You should also examine the file JU:SPEAK for an example of opening a device and calling DoIO and other Exec calls. 
  818. DEMO__SPRITE  -  This demonstrates the creation and use of a hardware sprite.  It bounces around on the screen leaving a textile like pattern.  If you let it go for a long time it will slowly change the color scheme.  You can modify the width and height to get different patterns.   
  819. DEMO_STRIP  -  No this is not pornography! Displays a simple running strip chart.
  820. Fibonacci  - Generates the Fibonacci numeric sequence.
  821. HIGH_INTERRUPT   - How to call high level Forth code from a 68000 interrupt. Be careful.
  822. LOAD_DEMOS  -  This contains a menu based program that integrates all of the other demos.  This could be used by retailers for customer demos.  
  823. SIEVE   - The legendary Sieve of Eratosthenes. Generates prime numbers which is sometimes useful for something besides benchmarking compilers.   
  824. JDEV:  -  JTools:DevTools  -  Development Tools
  825. BLOCK   - Support for old style Forth BLOCK or SCREEN environment.   
  826. BLOCK2TEXT   - Convert an old style Forth BLOCK based file to a normal text file.
  827. * DEBUGGER   - Source level debugger. This allows you to single step through your code while examining the stack, etc.   
  828. EDITOR   - Old style FIG Forth line editor. As in Leo Brodie's starting Forth.  We recommend using the more modern text editors or SCRED.   
  829. PROFILE   - Analyses code performance so you know what to optimize.
  830. SCRED   - Screen based block editor, WYSIWYG.  Almost enough to make you want to use BLOCKs.   
  831. UNUSED   - Mark words as used when compiling a file.  Handy for stripping old extraneous code out of a system.   
  832. WORDCACHE   - Caches recently entered words for word completion using a function key.
  833. JF:  -  Extras:Sysgen  -  System Generation
  834. The JF: files are necessary for any JForth image...they are loaded on top of the com:JKernal image to produce the com:JForth image, which may be further customized as the programmer sees fit for his particular programming needs.   
  835. These files allow the programmer to modify the JForth system at a relatively low level; he may alter and regenerate all but the bottom 23K of code which was written in assembler.  
  836. Here is a partial listing of those files.
  837. $TABLE  - String Table, string arrays used by disassembler.   
  838. .IF   - Conditional compilation.
  839. @BITS   -
  840. AJF_DICT   - low level support for C_STRUCT and ODE.
  841. ANSI    - Support for the ANSI terminal escape sequences for fancy screen displays.  Change colors, underline, italics, move cursor, etc.   
  842. ASM     - Reverse Polish 68000 assembler.  In a precompiled module.
  843. AUTO    - Contains an AUTO.INIT that provides a way of passing a command to JForth from the CLI. 
  844. BUILDSYS   - lowest level Forth code.  Everything below this was written in assembler.  Contains IF ELSE THEN and other important stuff.
  845. CALLS   - support calls to Amiga libraries.
  846. CASE   - CASE OF ENDOF ENDCASE conditionals.
  847. C_STRUCT        - Support for the Amiga 'C' structures.   
  848. CONDITION       - Exotic conditional construct similar to CASE.   
  849. DISM    - Disassembler. Shows you the 68000 code of a word.   
  850. DOSCOMMANDS     - Support easy DOS calls from Forth, eg. DIR , COPY  
  851. FORWARD-ASM     - Motorola style forward assembler.  This uses the more familiar 68000 assembler syntax.   
  852. HASHING - Hashes the Forth dictionary for faster compilation.   
  853. HISTORY - Provide Command Line History and hot Function Keys.   
  854. LOADJFORTH      - Loads the com:JForth image from com:Minimum.  You may want to customize this and recompile.
  855. MAKEINCLUDES    - Compile the includes module.  You may want to add more to this.   
  856. MEASURE - Measure how long it takes to execute something.  Great for running benchmarks.   
  857. MEMBER   - Support for structure members , ..@ and ..@  
  858. MODULE   - Support for precompiled modules of code like the INCLUDES.   
  859. SELECT   - Positional case statement. Warning    - will not clone!  Use CASE or a run-time initialized jump table.   
  860. STRING-INTERPRET        - Interpret a string containing Forth code.   
  861. STRIP-PATHNAME  - Strip the path, if any, from a filename.   
  862. TRAPS   - Trap 68000 exceptions to eliminate some GURU meditation errors.   
  863. WORDS-LIKE      - Searches dictionary words that contain a substring.  Very handy if you can't remember exactly how a word was spelled or for finding related words.   
  864. Y-OR-QUIT       - Ask the user to answer yes, no or quit.   
  865. JFLT:  -  Extras:Floats  -  Floating Point
  866. FLOAT.FFP   - Single Precision Floating Point Math  
  867. FLOAT.DOUBLE   - Double Precision Floating Point Math  
  868. JI:  -  JForth:Include     
  869. The Include directory contains the JForth-equivalent of the conventional C-language ".h" files.  The same file and directory structure has been maintained; the only difference is that the filename suffix is '.j'.  The files may be compiled via the normal JForth 'include' command;  they are referenced with the nickname 'ji:'.   Some of these files have been precompiled into a module called INCLUDES.
  870. JIFF:  -  Extras:IFF  -  Interchange File Format
  871. This directory contains the files to support the IFF standard.  This is the standard that is used for exchanging pictures, samples or other information between different programs.   See chapters 21 and 22. See also JANIM: in this chapter.
  872. DOUBLE_BUFFER   - Support for creating double buffered displays which can result in smoother animations.
  873. IFF.J   - Structure definitions and Chunk ID definitions, eg. 'FORM', are defined here.   
  874. IFF_SUPPORT     - Miscellaneous tools for recursively parsing an IFF file.   
  875. ILBM_MAKER     - Tools for creating an InterLeaved BitMap file.
  876. ILBM_PARSER     - Tools for parsing/reading an InterLeaved BitMap file.
  877. LOAD_PIC   - Loads Picture system.
  878. PACKING  -  Routines for packing Bitmaps into BODY chunks and for packing CTABLES into CMAP chunks.
  879. PIC_EFFECTS  -  Special effects for IFF Pictures like wipes and fades.
  880. PIC_FLIP   - reverse and flip a picture.
  881. PICTURES  -  Picture Animation that allows you to load IFF pictures and perform simple animations, page flipping, transparent blitting, etc.
  882. SHOW_IFF       - Example program to display an ILBM graphics picture, plus tools for transparently copying brush bitmaps to a screen.   
  883. UNPACKING       - The assembly routine for unpacking a Run Length Encoded bitmap, an Uncompressed bitmap, and a CMAP.   
  884. TEST_PIC   - Simple test/demo of picture system.
  885. JO:  -  Extras:ODE  -  Object Development Environment  
  886. This directory contains source code for ODE, the Object Oriented Development Environment.   Please see the chapter on ODE.
  887. JPICS:  -  JTools:JPics   - Pictures for tutorials
  888. These IFF pictures are used by the test programs and tutorials of the IFF and ANIM Support systems.
  889. JRX:  -  JTools:JARexx  -  Arexx Interface
  890. Tools for writing ARexx compatible applications.  See chapter on ARexx for a description of the files.
  891. JTX:  -  JTools:Textra_Dir  -  Text Editor
  892. Textra is a public domain text editor written in JForth by Mike Haas.  It can be integrated with JForth using ARexx.  See the docs on disk and the chapter on ARexx interfacing.  A subdirectory in JTX: contains scripts which can be copied to your REXX: directory for use with Textra.
  893. JU:  -  JForth:Util  -  Utilities
  894. This directory contains a wide variety of tools and utilities.  We have divided them into two categories, general purpose Forth utilities and Amiga specific utilities.  Files that we think are particularly important are marked with a single asterisk, '*'.
  895. Note: Some of the files that were in JU: in Version 2.0 had to be moved because of disk space constraints.  Look in JF:, JDEV:, and JFLT: for these files.
  896. General Forth Utilities
  897. .RSTACK - Dump return stack, like .S .   
  898. * BSEARCH - Binary search using a deferred word.   
  899. * BSORT   - Batcher sort for sorting anything pretty quick.   
  900. CATCH   - A way to trap errors and jump back to the caller.   
  901. * CHAR-MACROS     - 'C' like character routines, ISDIGIT , TOUPPER  
  902. * DOLINES - Provides a simple way of processing the lines of a file using a deferred word.   
  903. * LOCALS  - Local variables.  These are handy for reducing the amount of stack manipulation in your program, ie. fewer DUPs , SWAPs and ROTs.   
  904. * LOGTO   - Copy the output of JForth to a file.  This can be used for echoing to the printer if you use PRT: as the file.   
  905. MORE-ARRAYS     - Different types of arrays, 2D arrays, record arrays, etc.   
  906. MSEC    - Millisecond timer, not very accurate.   
  907. MODULEFIND   - More module support.   
  908. * MULTISTANDARD   - Provides compatibility with Forth-79, FIG and Forth '83 standards.  Look here for common words you expected to find in JForth.   
  909. RAM-WORDS       - Handy word for using RAM: when editing large files.   
  910. * RANDOM  - 16 bit pseudo-random number generator.   
  911. RELOAD  - Reload a part of a program that uses multiple files.   
  912. SFA_BITS        - defines bits in Size Field  
  913. SHOWHUNKS       - Dump out the hunks in an Amiga binary file using the Disassembler. Great for exploring how things work.   
  914. SQRT    - Calculate integer square roots fast.   
  915. STACKUTILS      - Dynamically expanding stacks. A useful data structure.   
  916. TURNKEY - Save a JForth image in a royalty free format.  These files are big so only use this as a last resort if your program won't Clone.   
  917. * UNRAVEL - Examine the return stack and tell you who called who.  Useful for debugging.   
  918. * VALUE   - Self fetching variable. Like a constant you can change.   
  919. Amiga Specific Utilities
  920. * AMIGA_EVENTS    - Support for getting IDCMP events.   
  921. * AMIGA_GRAPH     - Library of primitive graphics routines to get you started.   
  922. * AMIGA_MENUS     - The EZMenu system which makes it much easier to use text based Intuition pull down menus.   
  923. ASL_SUPPORT   - Calls to Application Specific Library plus special support for a file and font requester.  These only work under Amiga DOS 2.0.
  924. ANSISUPPORT     - More general support for ANSI code.   
  925. AUTO_REQUEST    - Easy way to put up an Amiga Auto Requestor.   
  926. CIAB_RSRC.F   - Calls into CIAB resource for parallel port interfacing.
  927. COLORDUMP   - 
  928. CONSOLESUPPORT  - Many tools for handling Console devices and RAW windows.   
  929. DEVICE-CALLS    - The special device calls, BEGINIO() and ABORTIO()  
  930. DOS-SUPPORT     - Some handy DOS tools, Lock() , Examine() , ExNext().   
  931. * DUMP_STRUCT     - Dump the contents of a structure with the member names.   
  932. ERROR_CODES   - Defines some sequential error return codes.
  933. EXAMINE - Print information about a file, eg. protection, size, date.   
  934. EXEC_LISTS      - Linked list macros.   
  935. * EXEC_SUPPORT    - Various EXEC library calls, eg. DoIO() , FindTask() , WaitPort() , etc.  Also the 'C' routines that are not in a library like CreatePort() , DeletePort() , CreateExtIO() , etc.   
  936. EZALERT - Simple interface to Amiga Alert.  Looks like a GURU message.   
  937. FDUMP   - Dump the contents of a file interactively. Like DUMP but in a file.   
  938. FILE-TOOLS      - More DOS file tools like FSIZE which gets file size. Read warning in file before using.
  939. GADGET_SUPPORT  - Tools for initializing and using Gadgets.   
  940. GETCC   - Commodore approved way of getting 68000 condition code register contents.
  941. GOTO_ERROR   - Provides a jump to an ERROR: label in a colon definition.
  942. * GRAPH_SUPPORT   - Miscellaneous graphics calls, bitmap tools.   
  943. ICON-SUPPORT    - Calls for Free Get and PutDiskObject()  
  944. POLYGON - Use Area draw routines to draw polygons, GR.TRIANGLE  
  945. SCREEN_SUPPORT  - NewScreen.Setup , OpenScreen() , Bitmap>Screen, Screen>View, etc.   
  946. SERIAL  - Support for RS232 serial device.   
  947. SET-ICON        - Associate an action with an icon.   
  948. SPEAK   - Simple interface to the narrator and translator libraries.   
  949. SPRITES - Support for hardware sprites.   
  950. 3 -      JForth Disk Organization
  951.  
  952.     JForth Disk Organization    3 -  
  953.  
  954.  
  955.  
  956.  
  957.  
  958. Chapter 4
  959. Beginning Forth Tutorial      
  960. Intended Audience      
  961. The intent of this tutorial is to provide a series of experiments that will introduce you to the major concepts of Forth.  It is only a starting point.  Feel free to deviate from the sequences I provide.  A free form investigation that is based on your curiosity is probably the best way to learn any language.  Forth is especially well adapted to this type of learning.   There are a number of excellent text books on Forth that you may want to use along with this tutorial.  Look in the bibliography for a list of books.  We recommend either Starting Forth or Forth: A Text and Reference.
  962. In the tutorials, I will print the things you need to type in upper case, and indent them.  You can enter them in upper or lower case.  At the end of each line, press the RETURN (or ENTER) key; this causes JForth to interpret what you've entered.
  963. Forth Syntax      
  964. Forth has one of the simplest syntaxes, or formats, of any computer language.  The syntax can be stated as follows, "Forth code is a bunch of words with spaces between them."  This is even simpler than English!  Each word is equivalent to a function or subroutine in a language like 'C'.  They are executed in the order they appear in the code.  The following statement, for example, could appear in a Forth program:
  965. WAKE.UP  EAT.BREAKFAST  WORK  EAT.DINNER  PLAY  SLEEP
  966. Notice that WAKE.UP has a dot between the WAKE and UP.  This is because it is one Forth word with a specific meaning.  Forth word names can have any combination of letters, numbers, or punctuation.  We will encounter words with names like:
  967.     ."  #S  SWAP MOVE !  @  .   *
  968. They are all called words.  The word $%%-GL7OP is a legal Forth name, although not a very good one.  It is up to the programmer to name words in a sensible manner.
  969. The Stack      
  970. The Forth language is based on the concept of a stack.  Imagine a stack of blocks with numbers on them.  You can add or remove numbers from the top of the stack.  You can also rearrange the order of the numbers.  Forth uses several stacks.  The Parameter Stack is the one used for passing data between Forth words so we will concentrate our attention there.  The Parameter Stack is also known as the Data Stack.  The Return Stack is another Forth stack that is primarily for internal system use.  In this tutorial, when we refer to the "stack," we will be referring to the Parameter Stack.   
  971. The stack is initially empty.  To put some numbers on the stack, enter:  
  972. 23 7 9182 
  973. You will notice that the OK message now has a '3' in front of it.  This tells you that there are three numbers on the stack.   
  974. Let's now print the number on top of the stack using the Forth word ' . ', which is pronounced " dot ".  This is a hard word to write about in a manual because it is a single period.   
  975. Enter:     .   
  976. You should see the last number you entered, 9,182 ,  printed.  Forth has a very handy word for showing you what's on the stack.  It is .S , which is pronounced "dot S".  The name was constructed from "dot" for print, and "S" for stack.  If you enter:  
  977. .S 
  978. you will see your numbers in a list.  The number at the far right is the one on top of the stack.   
  979. You will notice that the 9182 is not on the stack.  The word ' . ' removes the number on top of the stack before printing it.  In contrast, ' .S ' leaves the stack untouched.   
  980. We have a way of documenting the effect of words on the stack with a stack diagram.  A stack diagram is contained in parentheses.  In Forth, the parentheses indicate a comment.  In the examples that follow, you do not need to type in the comments.  When you are programming, of course, we encourage the use of comments and stack diagrams to make your code more readable.  In this manual, we often indicate stack diagrams in bold text like the one that follows.  Do not type these in.  The stack diagram for a word like ' . ' would be:  
  981. . ( N -- , print number on top of stack ) 
  982. The symbols to the left of -- describe the parameters that a word expects to process.  In this example, N stands for any integer number.  To the right of --, up to the comma, is a description of the stack parameters when the word is finished, in this case there are none because 'dot' "eats" the N that was passed in.  (Note that the stack descriptions are not necessary, but they are a great help when learning other peoples programs.)
  983. The text following the comma is an English description of the word.  You will note that after the -- , N is gone.  You may be concerned about the fact that there were other numbers on the stack, namely 23 and 7 .  The stack diagram, however, only describes the portion of the stack that is affected by the word.  For a more detailed description of the stack diagrams, there is a special section on them in this manual right before the main glossary section.  
  984. Between examples, you will probably want to clear the stack.  If you enter 0SP, pronounced "zero S P", then the stack will be cleared.   
  985. Since the stack is central to Forth, it is important to be able to alter the stack easily.  Let's look at some more words that manipulate the stack.  Enter:  
  986. 0SP .S    \ That's a 'zero' 0, not an 'oh' O.
  987. 777 DUP .S 
  988. You will notice that there are two copies of 777 on the stack.  The word DUP duplicates the top item on the stack.  This is useful when you want to use the number on top of the stack and still have a copy.  The stack diagram for DUP would be:  
  989. DUP ( n -- n n , DUPlicate top of stack ) 
  990. Another useful word, is SWAP. Enter:  
  991. 0SP 
  992. 23 7 .S 
  993. SWAP .S 
  994. SWAP .S 
  995. The stack diagram for SWAP would be:  
  996. SWAP ( a b -- b a , swap top two items on stack ) 
  997. Now enter:  
  998. OVER .S 
  999. OVER .S 
  1000. The word OVER causes a copy of the second item on the stack to leapfrog over the first. It's stack diagram would be:  
  1001. OVER ( a b -- a b a , copy second item on stack )
  1002. Here is another commonly used Forth word:
  1003. DROP  ( a -- , remove item from the stack )
  1004. Can you guess what we will see if we enter:
  1005. 0SP 11 22 .S
  1006. DROP .S
  1007. Another handy word for manipulating the stack is ROT.  Enter:
  1008. 0SP 
  1009. 11 22 33 44 .S 
  1010. ROT .S 
  1011. The stack diagram for ROT is, therefore:  
  1012. ROT  ( a b c -- b c a , ROTate third item to top )  
  1013. You have now learned the more important stack manipulation words.  You will see these in almost every Forth program.  I should caution you that if you see too many stack manipulation words being used in your code then you may want to reexamine and perhaps reorganize your code.  You will often find that you can avoid excessive stack manipulations by using local or global VARIABLES which will be discussed later.   
  1014. If you want to grab any arbitrary item on the stack, use PICK .  Try entering:  
  1015. 0SP
  1016. 14 13 12 11 10 
  1017. 3 PICK .    ( prints 13 )
  1018. 0 PICK .    ( prints 10 )
  1019. 4 PICK .  
  1020. PICK makes a copy of the Nth item on the stack.  The numbering starts with zero, therefore:  
  1021. 0 PICK   is equivalent to DUP 
  1022. 1 PICK   is equivalent to OVER 
  1023. PICK  ( ... v3 v2 v1 v0 N -- ... v3 v2 v1 v0 vN )  
  1024. (Warning. The Forth-79 and FIG Forth standards differ from the Forth '83 standard in that their PICK numbering starts with one, not zero.)  
  1025. I have included the stack diagrams for some other useful stack manipulation words.  Try experimenting with them by putting numbers on the stack and calling them to get a feel for what they do.  Again, the text in parentheses is just a comment and need not be entered.
  1026. DROP  ( n -- , remove top of stack )  
  1027. ?DUP  ( n -- n n | 0 , duplicate only if non-zero, '|' means OR )  
  1028. -ROT  ( a b c -- c a b , rotate top to third position )  
  1029. 2SWAP ( a b c d -- c d a b , swap pairs )  
  1030. 2OVER ( a b c d -- a b c d a b , leapfrog pair )  
  1031. 2DUP  ( a b -- a b a b , duplicate pair )  
  1032. 2DROP ( a b -- , remove pair )  
  1033. NIP   ( a b -- b , remove second item from stack )  
  1034. TUCK  ( a b -- b a b , copy top item to third position )  
  1035.  
  1036. Problems:
  1037. Start each problem by entering:  
  1038. 0SP 11 22 33 
  1039. Then use the stack manipulation words you have learned to end up with the following numbers on the stack:  
  1040. 1)      11 33 22 22 
  1041.  
  1042. 2)      22 33 
  1043.  
  1044. 3)      22 33 11 11 22 
  1045.  
  1046. 4)      11 33 22 33 11 
  1047.  
  1048. 5)      33 11 22 11 22 
  1049.  
  1050. Answers to the problems can be found at the end of all the tutorials.   
  1051. Arithmetic       
  1052. Great joy can be derived from simply moving numbers around on a stack. Eventually, however, you'll want to do something useful with them.  This section describes how to perform arithmetic operations in Forth.   
  1053. The Forth arithmetic operators work on the numbers currently on top of the stack.  If you want to add the top two numbers together, use the Forth word  + , pronounced "plus".  Enter:  
  1054. 2 3 + .  
  1055. 2 3 + 10 + .  
  1056. This style of expressing arithmetic operations is called Reverse Polish Notation, or RPN.  It will already be familiar to those of you with HP calculators.  In the following examples, I have put the algebraic equivalent representation in a comment.
  1057. Some other arithmetic operators are  - * / . Enter:
  1058. 30 5 - .  ( 25=30-5 )
  1059. 30 5 / .  ( 6=30/5 )
  1060. 30 5 * .  ( 150=30*5 )
  1061. 30 5 + 7 / .  \  5=(30+5)/7
  1062. Some combinations of operations are very common and have been coded in assembly language for speed.  For example, 2* is short for 2 * .  You should use these whenever possible to increase the speed of your program. These include:  
  1063. 1+  1-  2+  2-  2*  2/ 
  1064. Try entering:  
  1065. 10 1- .  
  1066. 7 2* 1+ .  ( 15=7*2+1 )
  1067. One thing that you should be aware of is that when you are doing division with integers using / , the remainder is lost. Enter:  
  1068. 15 5 / .  
  1069. 17 5 / .  
  1070. This is true in all languages on all computers.  Later we will examine /MOD and MOD which do give the remainder.   
  1071. Defining a New Word    
  1072. It's now time to write a small program in Forth.  You can do this by defining a new word that is a combination of words we have already learned.  Let's define and test a new word that takes the average of two numbers.   
  1073. We will make use of two new words, : ( "colon"), and ; ( "semicolon") .  These words start and end a typical Forth definition.  When you type this in, you may want to time how long it takes between hitting the RETURN key and the appearance of the OK prompt.  This will be how long it takes Forth to compile and link this small program.  Enter:  
  1074. : AVERAGE  ( a b -- avg )  + 2/   ; 
  1075. Congratulations. You have just written a Forth program.  If you are used to 'C', you were probably wondering what to get from the kitchen while compiling.  One danger of programming in Forth is that, once hooked, you may never take time to eat.
  1076. Let's look more closely at what just happened.  The colon told Forth to add a new word to its list of words.  This list is called the Forth dictionary.  The name of the new word will be whatever name follows the colon.  Any Forth words entered after this will be compiled into the new word.  This continues until the semicolon is reached which finishes the definition.
  1077. Let's test this word by entering:  
  1078. 10 20 AVERAGE .  ( should print 15 )
  1079. Once a word has been defined, it can be used to define more words.  Let's write a word that tests our word..  Enter:
  1080. : TEST ( --)  50 60 AVERAGE . ;
  1081. TEST
  1082. Try combining some of the words you have learned into new Forth definitions of your choice.  If you promise not to be overwhelmed, you can get a list of the words that are available for programming by entering:  
  1083. WORDS 
  1084. You can stop this listing by hitting the space bar.  To continue, hit the return key.  To stop, type:
  1085. QUIT 
  1086. Don't worry, only a small fraction of these will be used directly in your programs.   
  1087. More Arithmetic
  1088. When you need to know the remainder of a divide operation. /MOD will return the remainder as well as the quotient.  the word MOD will only return the remainder.  Enter:  
  1089. 0SP
  1090. 53 10 /MOD .S 
  1091. 0SP  
  1092. 7 5 MOD .S
  1093. Two other handy words are MIN and MAX .  They accept two numbers and return the MINimum or MAXimum value respectively.  Try entering the following:  
  1094. 56 34 MAX .  
  1095. 56 34 MIN .  
  1096. -17 0 MIN .  
  1097. Some other useful words are:  
  1098. ABS    ( n -- abs(n) , absolute value of n )  
  1099. NEGATE ( n -- -n , negate value, faster then -1 * )  
  1100. ASHIFT ( n c -- n*(2**c) , arithmetic shift of n )  
  1101. SHIFT  ( n c -- n' , logical shift of n )  
  1102. ASHIFT can be used if you have to multiply quickly by a power of 2 .  A negative count is like doing a divide.  This is much faster than doing a regular multiply and should be used whenever possible.  Try entering:  
  1103. : 256*   8 ASHIFT ; 
  1104. 3 256* .  
  1105. Arithmetic Overflow
  1106. If you are having problems with your calculation overflowing the 32-bit precision of the stack, then you can use */ .  This produces an intermediate result that is 64 bits long.  Try the following three methods of doing the same calculation.  Only the one using */ will yield the correct answer, 5197799.   
  1107. 34867312 99154 * 665134 / .  
  1108. 34867312 665134 / 99154 * .  
  1109. 34867312 99154 665134 */ .  
  1110. Convert Algebraic Expressions to Forth
  1111. How do we express complex algebraic expressions in Forth?   For example:   20 + (3 * 4)
  1112. To convert this to Forth you must order the operations in the order of evaluation.  In Forth, therefore, this would look like:  
  1113. 3 4 *  20 +
  1114. Evaluation proceeds from left to right in Forth so there is no ambiguity.  Compare the following algebraic expressions and their Forth equivalents: (Do not enter these!)
  1115. (100+50)/2   ==>  100 50 +  2/
  1116. ((2*7) + (13*5))  ==>  2 7 *  13 5 *  +
  1117.  If any of these expressions puzzle you, try entering them one word at a time, while viewing the stack with .S .   
  1118. Problems:  
  1119. Convert the following algebraic expressions to their equivalent Forth expressions.  (Do not enter these because they are not Forth code!)
  1120. (12 * ( 20 - 17 )) 
  1121. (1 - ( 4 * (-18) / 6) )
  1122. ( 6 * 13 ) - ( 4 * 2 * 7 ) 
  1123. Use the words you have learned to write these new words:  
  1124. SQUARE   ( N -- N*N , calculate square )  
  1125. DIFF.SQUARES ( A B -- A*A-B*B , difference of squares )  
  1126. AVERAGE4  ( A B C D -- [A+B+C+D]/4 )  
  1127. HMS>SECONDS ( HOURS MINUTES SECONDS -- TOTAL-SECONDS , convert )  
  1128. Character Input and Output    
  1129. The numbers on top of the stack can represent anything.  The top number might be how many blue whales are left on Earth or your weight in kilograms.  It can also be an ASCII character.  Try entering the following:  
  1130. 72 EMIT  105 EMIT 
  1131. You should see the word "Hi" appear before the OK.  The 72 is an ASCII 'H' and 105 is an 'i'.  EMIT takes the number on the stack and outputs it as a character.  If you want to find the ASCII value for any character, you can use the word ASCII . Enter: 
  1132. ASCII W .  
  1133. ASCII %   DUP .   EMIT 
  1134. ASCII A   DUP .  
  1135. 32 + EMIT 
  1136. There is an ASCII chart in the back of this manual for a complete character list.
  1137. Notice that the word ASCII is a bit unusual because its input comes not from the stack, but from the following text.  In a stack diagram, we represent that by putting the input in angle brackets, <input>.  Here is the stack diagram for ASCII.
  1138. ASCII  ( <char> -- char , get ASCII value of a character )  
  1139. Using EMIT to output character strings would be very tedious.  Luckily there is a better way.  Enter:  
  1140. : TOFU ." Yummy bean curd!" ; 
  1141. TOFU 
  1142. The word ." , pronounced "dot quote",  will take everything up to the next quotation mark and print it to the screen.  Make sure you leave a space after the first quotation mark.  When you want to have text begin on a new line, you can issue a carriage return using the word CR .  Enter:  
  1143. : SPROUTS ." Miniature vegetables." ; 
  1144. : MENU 
  1145.     CR TOFU CR SPROUTS CR 
  1146. MENU 
  1147. You can emit a blank space with SPACE .  A number of spaces can be output with SPACES .  Enter:  
  1148. CR TOFU SPROUTS 
  1149. CR TOFU SPACE SPROUTS 
  1150. CR 10 SPACES TOFU CR 20 SPACES SPROUTS 
  1151. For character input, Forth uses the word KEY which corresponds to the word EMIT for output.  KEY waits for the user to press a key then leaves its value on the stack.  Try the following.   
  1152. : TESTKEY ( -- ) 
  1153.     ." Hit a key: " KEY CR 
  1154.     ." That = " . CR 
  1155. TESTKEY 
  1156. EMIT   ( char -- , output character )  
  1157. KEY    ( -- char , input character )  
  1158. SPACE  ( -- , output a space )  
  1159. SPACES ( n -- , output n spaces )  
  1160. ASCII  ( <char> -- char , convert to ASCII )  
  1161. CR     ( -- , start new line , carriage return )  
  1162. ."     ( -- , output " delimited text )  
  1163. Answers to Problems
  1164. If your answer doesn't exactly match these but it works, don't fret.  In Forth, there are usually many ways to the same thing.   
  1165. Stack Manipulations  
  1166. 1) SWAP DUP 
  1167. 2) ROT DROP 
  1168. 3) ROT DUP 3 PICK 
  1169. 4) SWAP OVER 3 PICK 
  1170. 5) -ROT 2DUP 
  1171. Arithmetic  
  1172. (12 * (20 - 17))    ==>   20 17 -  12 * 
  1173.  
  1174. (1 - (4 * (-18) / 6))     ==>   1   4 -18 *  6 /  - 
  1175.  
  1176. (6 * 13) - (4 * 2 * 7)    ==>   6 13 *  4 2 *  7 *   - 
  1177.  
  1178. : SQUARE ( N -- N*N ) 
  1179.     DUP * 
  1180. : DIFF.SQUARES ( A B -- A*A-B*B ) 
  1181.     SWAP SQUARE 
  1182.     SWAP SQUARE - 
  1183. : AVERAGE4 ( A B C D -- [A+B+C+D]/4 ) 
  1184.     + + +   ( add'em up ) 
  1185.     -2 ashift ( divide by four the fast way, or 4 / ) 
  1186. : HMS>SECONDS  ( HOURS MINUTES SECONDS -- TOTAL-SECONDS ) 
  1187.     -ROT SWAP ( -- seconds minutes hours ) 
  1188.     60 * +    ( -- seconds total-minutes ) 
  1189.     60 * +    ( -- seconds ) 
  1190.  
  1191. 4 -      Beginning Forth Tutorial
  1192.  
  1193.     Beginning Forth Tutorial    4 -  
  1194.  
  1195.  
  1196.  
  1197.  
  1198.  
  1199. Chapter 5
  1200. Intermediate Forth Tutorial
  1201. Note:  This chapter is shared between the JForth Manual and the HMSL manual.  Information specific to HMSL on the Macintosh or JForth on the Amiga is noted as such.
  1202. Editing Programs in Files
  1203. As your programs get larger, it becomes impractical to type them in fresh each time.  To develop software of any size, you'll need to keep your source code in files.  You can then compile directly from these files instead of from the keyboard.  Forth programs can be created like programs in other languages by using a text editor.  You can use any text editor that you like.  Beware of word processing programs because they will put strange information in the file related to margins, fonts, etc.  If you use a word processor, save the file in text only mode.  We recommend that you use the text editor that comes included with your Forth package.  The process of editing differs between computers.  Please read the appropriate section for your machine
  1204. Editing on the Macintosh:  To create a new file, select New from the File menu while in Forth.  Text can be enterred in the standard Macintosh style.  Look in the Edit menu for commands like Cut, Copy and Paste, Upper and Lower case conversion.
  1205. Editing on the Amiga:  The editor supplied with JForth is called Textra.  It was written by Mike Haas using JForth.  Full documentation on Textra is supplied in the JTX:DOCS directory.  You will probably want to install Textra by either copying it to your C: directory (or any other directory in your current AmigaDOS path) or to a place convienient for double-clicking it's icon.  Textra can be found in the JTX: directory on the JTOOLS: disk.  Assuming Textra is installed, either double-click on it's icon or enter:
  1206. RUN TEXTRA
  1207. If you want to open an existing file, select it using the file selector.  To start with a fresh file, hit CANCEL.  Look in the Project menu for commands to save files and to create new files.
  1208. You can move through the file using cursor keys or the mouse.  Drag the mouse (while holding down the left mouse button) to select text.  Selected text can be Cut, Copied, or Pasted using commands in the Edit menu.
  1209. If you have ARexx, look in Chapter 23, AREXX Support for instructions on how to connect JForth and Textra for easy compilation.
  1210. Sample Program
  1211. Enter into your file, the following code.  
  1212. \ Sample Forth Code 
  1213. \ Author: your name 
  1214. : SQUARE  ( n -- n*n , square number ) 
  1215.     DUP * 
  1216. : TEST.SQUARE ( -- )
  1217.     CR ." 7 squared = " 
  1218.     7 SQUARE . CR 
  1219. Now save the file as described for your machine.
  1220. The text following the \ character is treated as a comment.  This would be a REM statement in BASIC or a /*---*/ in 'C'.  The text in parentheses is also a comment.   
  1221. Save this file using the "Save As..."  menu option, giving it the name SAMPLE in the process.
  1222. INCLUDE the Program
  1223. "INCLUDE" in Forth means to compile from a file. 
  1224. Compiling on the Macintosh:  To compile a file directly from the editor, select the "Include From Editor" command from the Include menu.  If an error is encountered, it will be highlighted in the editor.  Error messages will appear in the Forth window.  You can also compile your program from HMSL by selecting "Include from File..." from the File menu.   Use the dialog to select the file you just created.
  1225. Compiling on the Amiga:  If you have ARexx installed, and configured Textra and JForth as described in Chapter 23, you can compile a file from Textra by simply hitting whichever  function key is assigned to the jcompile command.  If an error is encountered, it will be highlighted in the editor.  Error messages will appear in the Forth window.
  1226. You can also compile from a file using the INCLUDE command.  If you saved your file as WORK:SAMPLE, then compile it by entering:
  1227. INCLUDE WORK:SAMPLE
  1228. Forth will compile your file and tell you how many bytes it has added to the dictionary.  To test your word, enter:  
  1229. TEST.SQUARE 
  1230. Your two words, SQUARE and TEST.SQUARE are now in the Forth dictionary. We can now do something that is very unusual in a programming language.  We can "uncompile" the code by telling Forth to FORGET it. Enter:  
  1231. FORGET SQUARE 
  1232. This removes SQUARE and everything that follows it, ie.  TEST.SQUARE, from the dictionary.  If you now try to execute TEST.SQUARE it won't be found.   
  1233. Now let's make some changes to our file and reload it.  Go back into the editor and make the following changes:  (1) Change TEST.SQUARE to use 15 instead of 7 then (2) Add this line right before the definition of SQUARE:
  1234. ANEW TASK-SAMPLE
  1235. Now Save your changes and go back to the Forth window.  
  1236. You're probably wondering what the line starting with ANEW was for.   ANEW is always used at the beginning of a file.  It defines a special marker word in the dictionary before the code.  The word typically has "TASK-" as a prefix followed by the name of the file.  When you ReInclude a file, ANEW will automatically FORGET the old code starting after the ANEW statement.  This allows you to Include a file over and over again without having to manually FORGET the first word.  If the code was not forgotten, the dictionary would eventually fill up.
  1237. If you have a big project that needs lots of files, you can have a file that will load all the files you need.  Sometimes you need some code to be loaded that may already be loaded.  The word INCLUDE? will only load code if it isn't already in the dictionary.   In this next example, I assume the file is on the volume WORK: and called SAMPLE.  If not, please substitute the actual name.  Enter:
  1238. FORGET TASK-SAMPLE
  1239. INCLUDE? SQUARE WORK:SAMPLE 
  1240. INCLUDE? SQUARE WORK:SAMPLE 
  1241. Only the first INCLUDE? will result in the file being loaded. 
  1242. Variables
  1243. Forth does not rely as heavily on the use of variables as other compiled languages.  This is because values normally reside on the stack.  There are situations, of course, where variables are required.  To create a variable, use the word VARIABLE as follows:  
  1244. VARIABLE MY-VAR 
  1245. This created a variable named MY-VAR .  A space in memory is now reserved to hold its 32-bit value.  The word VARIABLE is what's known as a "defining word" since it creates new words in the dictionary.  Now enter:  
  1246. MY-VAR .  
  1247. The number you see is the address, or location, of the memory that was reserved for MY-VAR.  To store data into memory you use the word ! , pronounced "store".  It looks like an exclamation point, but to a Forth programmer it is the way to write 32-bit data to memory.  To read the value contained in memory at a given address, use the Forth word @ , pronounced "fetch".  Try entering the following:  
  1248. 513 MY-VAR ! 
  1249. MY-VAR @ .  
  1250. This sets the variable MY-VAR to 513 , then reads the value back and prints it.  The stack diagrams for these words follows:  
  1251. @  ( address -- value , FETCH value FROM address in memory )  
  1252. !  ( value address -- , STORE value TO address in memory )
  1253. VARIABLE  ( <name> -- , define a 4 byte memory storage location)
  1254. A handy word for checking the value of a variable is ? , pronounced "question". Try entering:  
  1255. MY-VAR ? 
  1256. If ? wasn't defined, we could define it as:  
  1257. : ? ( address -- , look at variable ) 
  1258.     @ .  
  1259. Imagine you are writing a game and you want to keep track of the highest score.  You could keep the highest score in a variable.  When you reported a new score, you could check it aginst the highest score.  Try entering this code in a file as described in the previous section:  
  1260. VARIABLE HIGH-SCORE 
  1261. : REPORT.SCORE  ( score -- , print out score ) 
  1262.     DUP CR ." Your Score = "   .   CR 
  1263.     HIGH-SCORE @ MAX   ( calculate new high ) 
  1264.     DUP ." Highest Score = "   .   CR 
  1265.     HIGH-SCORE !       ( update variable ) 
  1266. Save the file to disk, then compile this code using the INCLUDE word.  Test your word as follows:  
  1267. 123 REPORT.SCORE 
  1268. 9845 REPORT.SCORE 
  1269. 534 REPORT.SCORE 
  1270. The Forth words @ and ! work on 32-bit quantities.  Some Forths are "16-bit" Forths.  They fetch and store 16-bit quantities.  Forth has some words that will work on 8 and 16-bit values.  C@ and C! work for 8-bit bytes.  The 'C' stands for "Character" since ASCII characters are 8-bit numbers.  Use W@ and W! for 16-bit "Words."  
  1271. Another useful word is +! , pronounced "plus store."  It adds a value to a 32-bit value in memory.  Try:  
  1272. 20 MY-VAR ! 
  1273. 5 MY-VAR +! 
  1274. MY-VAR @ .
  1275. Forth also provides some other words that are similar to VARIABLE.  Look in the glossary for VALUE and ARRAY.  Also look at the section on "local variables" which are variables which only exist on the stack while a Forth word is executing.
  1276. A word of warning about fetching and storing to memory:  You have now learned enough about Forth to be dangerous.  The operation of a computer is based on having the right numbers in the right place in memory.  You now know how to write new numbers to any place in memory.  Since an address is just a number, you could, but shouldn't, enter:  
  1277. 73 253000 ! ( Do NOT do this. ) 
  1278. The 253000 would be treated as an address and you would set that memory location to 73.  I have no idea what will happen after that, maybe nothing.  This would be like firing a rifle through the walls of your apartment building.  You don't know who or what you are going to hit. Since you share memory with other programs including the operating system, you could easily cause the computer to behave strangely, even crash.  Don't let this bother you too much, however.  Crashing a computer, unlike crashing a car, does not hurt the computer.  You just have to reboot.  The worst that could happen is that if you crash while the computer is writing to a disk, you could lose a file.  That's why we make backups.  This same potential problem exists in any powerful language, not just Forth.  This might be less likely in BASIC, however, because BASIC protects you from a lot of things, including the danger of writing powerful programs.   
  1279. Another way to get into trouble is to do what's called an "odd address memory access."  The 68000 processor arranges words and longwords, 16 and 32 bit numbers, on even addresses.  If you do a @ or ! , or W@ or W! , to an odd address, the 68000 processor will take exception to this and try to abort.  
  1280. Forth gives you some protection from this by trapping this exception and returning you to the OK prompt.  If you really need to access data on an odd address, check out the words ODD@ and ODD! in the glossary.  C@ and C! work fine on both odd and even addresses.  
  1281. ("Odd address errors" are not possible on Amiga's that use 68020 CPU's and later...they are made to perform this type of operation.  However, if you have one of these newer CPU's, you should always be mindful of all the Amiga's which DO use 68000's and avoid doing such operations.)  
  1282. The reason I am spending so much time on this is that if your program is crashing and getting those little pictures of bombs, you may likely be storing somewhere you shouldn't be.
  1283. Constants
  1284. If you have a number that is appearing often in your program, we recommend that you define it as a "constant." Enter:
  1285. 128 CONSTANT MAX_CHARS
  1286. MAX_CHARS .
  1287. We just defined a word called MAX_CHARS that returns the value on the stack when it was defined.  It cannot be changed unless you edit the program and recompile.  Using CONSTANT can improve the readability of your programs and reduce some bugs.  Imagine if you refer to the number 128 very often in your program, say 8 times.  Then you decide to change this number to 256.  If you globally change 128 to 256 you might change something you didn't intend to.  If you change it by hand you might miss one, especially if your program occupies more than one file.  Using CONSTANT will make it easy to change.  The code that results is equally as fast and small as putting the numbers in directly.  I recommend defining a constant for almost any number.
  1288. Logical Operators      
  1289. These next two sections are concerned with decision making.  This first section deals with answering questions like "Is this value too large?" or "Does the guess match the answer?".  The answers to questions like these are either TRUE or FALSE.  Forth uses a 0 to represent FALSE and a -1 to represent TRUE.  TRUE and FALSE have been capitalized because they have been defined as Forth constants.  Try entering:  
  1290. 23 71 = .  
  1291. 18 18 = .  
  1292. You will notice that the first line printed a 0, or FALSE, and the second line a -1, or TRUE.  The equal sign in Forth is used as a question, not a statement.  It asks whether the top two items on the stack are equal.  It does not set them equal.  There are other questions that you can ask. Enter:  
  1293. 23 198 < .  
  1294. 23 198 > .  
  1295. 254 15 > .  
  1296. In California, the drinking age for alcohol is 21.  You could write a simple word now to help bartenders.  Enter:  
  1297. : DRINK? ( age -- flag , can this person drink? ) 
  1298.     20 > 
  1299. 20 DRINK? .  
  1300. 21 DRINK? .  
  1301. 43 DRINK? .
  1302. The word FLAG in the stack diagram above refers to a logical value.
  1303. Forth provides special words for comparing a number to 0.  They are 0= 0> and 0< .  Using 0> is faster than calling 0 and > separately.  Enter:
  1304. 23 0> .  ( print -1 )
  1305. -23 0> . ( print 0 )
  1306. 23 0= .  ( print 0 )
  1307. For more complex decisions, you can use the Boolean operators OR , AND , and NOT . OR returns a TRUE if either one or both of the top two stack items are true.  
  1308. TRUE TRUE OR .  
  1309. TRUE FALSE OR .  
  1310. FALSE FALSE OR .  
  1311. AND only returns a TRUE if both of them are true.  
  1312. TRUE TRUE AND .  
  1313. TRUE FALSE AND .  
  1314. NOT reverses the value of the flag on the stack.  Enter:  
  1315. TRUE .  
  1316. TRUE NOT .  
  1317. Logical operators can be combined.
  1318. 56 3 >    56 123 < AND .  
  1319. 23 45 =   23 23 = OR .  
  1320. Here are stack diagrams for some of these words.  See the glossary for a more complete list.
  1321. < (  a b -- flag , flag is true if A is less than B )
  1322. > (  a b -- flag , flag is true if A is greater than B )
  1323. = (  a b -- flag , flag is true if A is equal to B )
  1324. 0=  ( a -- flag , true if a equals zero )
  1325. OR  ( a b -- a||b , perform logical OR of bits in A and B )
  1326. AND  ( a b -- a&b , perform logical AND of bits in A and B )
  1327. NOT  ( flag -- opposite-flag , true if false, false if true )
  1328. Problem:  
  1329. 1) Write a word called LOWERCASE? that returns TRUE if the number on top of the stack is an ASCII lowercase character.   An ASCII 'a' is 97 . An ASCII 'z' is 122 . Test using the characters " A a q z { ". 
  1330. ASCII A LOWERCASE? .    ( should print 0 )
  1331. ASCII a LOWERCASE? .    ( should print -1 )
  1332. Flow of Control     
  1333. You will now use the TRUE and FALSE flags you learned to generate in the last section.  The "flow of control" words accept flags from the stack, and then possibly "branch" depending on the value.  Enter the following code.   
  1334. : .L ( flag -- , print logical value ) 
  1335.     IF ." True value on stack!" 
  1336.     ELSE ." False value on stack!" 
  1337.     THEN 
  1338. 0 .L 
  1339. FALSE .L 
  1340. TRUE .L
  1341. 23 7 < .L
  1342. You can see that when a TRUE was on the stack, the first part got executed.  If a FALSE was on the stack, then the first part was skipped, and the second part was executed.  One thing you will find interesting is that if you enter:  
  1343. 23 .L 
  1344. the value on the stack will be treated as true.  The flow of control words consider any value that does not equal zero to be TRUE.   
  1345. The ELSE word is optional in the IF...THEN construct.  Try the following:  
  1346. : BIGBUCKS? ( ammount -- ) 
  1347.     1000 > 
  1348.     IF ." That's TOO expensive!" 
  1349.     THEN 
  1350. 531 BIGBUCKS? 
  1351. 1021 BIGBUCKS? 
  1352. Forth also has a CASE statement similar to switch() in 'C'.  Enter:  
  1353. : TESTCASE ( N -- , respond appropriately ) 
  1354.     CASE 
  1355.         0 OF  ." Just a zero!" ENDOF 
  1356.         1 OF  ." All is ONE!"  ENDOF 
  1357.         2 OF  WORDS            ENDOF 
  1358.         DUP . ." Invalid Input!" 
  1359.     ENDCASE CR 
  1360. 0 TESTCASE 
  1361. 1 TESTCASE 
  1362. 5 TESTCASE 
  1363. See CASE in the glossary for more information.
  1364. Problems:
  1365. 1) Write a word called DEDUCT that subtracts a value from a variable containing your checking account balance.  Assume the balance is in dollars.  Print the balance. Print a warning if the balance is negative.
  1366. VARIABLE  ACCOUNT
  1367. : DEDUCT ( n -- , subtract N from balance )
  1368.     ?????????????????????????????????  ( you fill  this in )
  1369. ;
  1370. 300 ACCOUNT !  ( initial funds )
  1371. 40 DEDUCT  ( prints 260 )
  1372. 200 DEDUCT ( print 60 )
  1373. 100 DEDUCT  ( print -40 and give warning! )
  1374. Loops
  1375. Another useful pair of words is BEGIN...UNTIL .  These are used to loop until a given condition is true.  Try this:  
  1376. : YAKYAK ( -- ) 
  1377.     BEGIN 
  1378.         ." I could talk all day!" CR 
  1379.         ?TERMINAL 
  1380.     UNTIL 
  1381. YAKYAK
  1382. This word will keep running until you hit a key on the keyboard.  The word ?TERMINAL will return TRUE if a key has been hit.  (You could then immediately call KEY if you wish to know what key was hit.)  
  1383. If you know how many times you want a loop to execute, you can use the DO...LOOP construct. Enter:  
  1384. : SPELL 
  1385.     ." ba" 
  1386.     4 0 DO 
  1387.         ." na" 
  1388.     LOOP 
  1389. This will print "ba" followed by four occurrences of "na".  The ending value is placed on the stack before the beginning value.  Be careful that you don't pass the values in reverse.  Forth will go "the long way around" which could take awhile.  The reason for this order is to make it easier to pass the loop count into a word on the stack.  Consider the following word for doing character graphics.  Enter:  
  1390. : PLOT# ( n -- ) 
  1391.     0 DO 
  1392.         ASCII -   EMIT 
  1393.     LOOP CR 
  1394. CR  9 PLOT#  37 PLOT# 
  1395. If you want to access the loop counter you can use the word I .  Here is a simple word that dumps numbers and their associated ASCII characters.   
  1396. : .CHARS ( end start -- , dump characters ) 
  1397.     DO 
  1398.         CR I . I EMIT 
  1399.     LOOP CR 
  1400. 80 64 .CHARS
  1401. You could make this word safe by making sure that the parameters are in the right order.  The word -2SORT will take two numbers and leave the smallest on top.  Enter:  
  1402. : SAFE.CHARS ( n1 n2 -- ) 
  1403.     -2SORT  ( put smallest on top ) 
  1404.     .CHARS 
  1405. 40 50 SAFE.CHARS 
  1406. 50 40 SAFE.CHARS
  1407. If you want to leave a DO LOOP before it finishes, you can use the word LEAVE.  Enter:  
  1408. : ANNOY.ME ( -- , Sing! ) 
  1409.     50000 0 
  1410.     DO  50000 I - .  
  1411.         ." bottles of beer on the wall." CR 
  1412.         ?TERMINAL ( was a key hit ) 
  1413.         IF  ." OK, I'll shut up!" CR 
  1414.             LEAVE  ( quit looping ) 
  1415.         THEN 
  1416.     LOOP 
  1417. Please consult the manual to learn about the following words +LOOP and RETURN . 
  1418. Another useful looping construct is the BEGIN WHILE REPEAT loop.  This allows you to make a test each time through the loop before you actually do something.  The word WHILE will continue looping if the flag on the stack is True.  Suppose you want to write a word called SHOWCHARS that prompts the user to hit a key, waits for a key to be hit, then prints the key as a decimal number and as a character.  It should keep doing this in a loop until the key is a 'q' or a 'Q'.  Here is a word that will do this:
  1419. : SHOWCHARS  ( -- , loop on chars till 'q' )
  1420.     BEGIN
  1421.         ." Hit a key or 'q' to quit:" KEY   ( wait for a key )
  1422.         DUP ASCII q =  ( -- char flag )
  1423.         OVER ASCII Q = OR NOT
  1424.     WHILE  ( -- char , loop if not 'q' or 'Q' )
  1425.         CR ." Key = " DUP . EMIT CR
  1426.     REPEAT DROP
  1427. ;
  1428. Text I/O      
  1429. You learned earlier how to do single character I/O.  This section concentrates on using strings of characters.  A text string in Forth consists of a character count in the first byte, followed immediately by the characters themselves.  A character string can be created using the Forth word " , pronounced 'quote'.  Note that you must follow the " by one space.  Any text following that space is copied to a special area in memory called the PAD.  The text string is terminated by an ending " .  Enter:  
  1430. " Fred" .  
  1431. The number that was printed was the address of the start of the string.  It should be a byte that contains the number of characters.  Now enter:  
  1432. " Fred" C@ .  
  1433. You should see a 4 printed.  Remember that C@ fetches one character/byte at the address on the stack.  By adding one to this address and doing a C@, you should see the first character.  Enter:  
  1434. " Fred" 1+ DUP C@ EMIT 
  1435. 1+ DUP C@ EMIT 
  1436. 1+ C@ EMIT 
  1437. Using this method, you could type out any string.  Luckily, there are two words that make this process much easier.  Enter:  
  1438. " Hello" COUNT .S 
  1439. TYPE 
  1440. The word COUNT extracts the number of characters and their starting address.  TYPE accepts the output of count and prints those characters. COUNT will only work with strings of less than 256 characters, since 255 is the largest number that can be stored in the count byte.  TYPE will, however, work with longer strings since the length is on the stack.  Their stack diagrams follow:  
  1441. COUNT  ( $addr -- addr #bytes , extract string information )  
  1442. TYPE   ( addr #bytes -- , output characters at addr )  
  1443. The $addr is the address of a count byte.  The dollar sign is often used to mark words that relate to strings.   
  1444. You can easily input a string using the word EXPECT.  (You may want to put these upcoming examples in a file since they are very handy.) The word EXPECT receives characters from the keyboard and places them at any specified address.  EXPECT takes input characters until a maximum is reached or a carriage return is entered.  The user variable SPAN contains the number of characters entered.  You can write a word for entering text. Enter:  
  1445. : INPUT$ ( -- $addr ) 
  1446.     PAD 1+  ( leave room for byte count ) 
  1447.     128 EXPECT  ( recieve a maximum of 128 chars ) 
  1448.     SPAN @   PAD C!  ( set byte count ) 
  1449.     PAD    ( return address of string ) 
  1450. You could use this in a program that writes form letters.   
  1451. : FORM.LETTER ( -- ) 
  1452.     ." Enter customer's name." CR 
  1453.     INPUT$ 
  1454.     CR ." Dear " DUP COUNT TYPE CR 
  1455.     ." Your cup that says " COUNT TYPE 
  1456.     ."  is in the mail!" CR 
  1457. EXPECT ( addr maxbytes -- , input text, save at address )  
  1458. SPAN   ( -- addr , contains number of chars EXPECT got )  
  1459. You can use your word INPUT$ to write a word that will read a number from the keyboard. Enter:  
  1460. : INPUT# ( -- N true | false ) 
  1461.     INPUT$  ( get string ) 
  1462.     NUMBER? ( convert to a string if valid ) 
  1463.     IF DROP TRUE  ( get rid of high cell ) 
  1464.     ELSE FALSE 
  1465.     THEN 
  1466. This word will return a single-precision number and a TRUE, or it will just return FALSE.  The word NUMBER? returns a double precision number if the input string contains a valid number.  Double precision numbers are 64-bit so we DROP the top 32 bits to get a single-precision 32 bit number. 
  1467. Changing Numeric Base     
  1468. Our numbering system is decimal, or "base 10."  This means that a number like 527 is equal to (5*100 + 2*10 + 7*1).  The use of 10 for the numeric base is a completely arbitrary decision.  It no doubt has something to do with the fact that most people have 10 fingers (including thumbs).  The Babylonians used base 60, which is where we got saddled with the concept of 60 minutes in an hour.  Computer hardware uses base 2, or "binary".  A computer number like 1101 is equal to (1*8 + 1*4 + 0*2 + 1*1).  If you add these up, you get 8+4+1=13 .  A 10 in binary is (1*2 + 0*1), or 2. Likewise 10 in any base N is N .   
  1469. Forth makes it very easy to explore different numeric bases because it can work in any base.  Try entering the following:  
  1470. DECIMAL  6   BINARY .  
  1471. 1 1 + .  
  1472. 1101 DECIMAL .
  1473. Another useful numeric base is hexadecimal.  which is base 16.  One problem with bases over 10 is that our normal numbering system only has digits 0 to 9.  For hex numbers we use the letters A to F for the digits 10 to 15.  Thus the hex number 3E7 is equal to (3*256 + 14*16 + 7*1).  Try entering:  
  1474. DECIMAL 
  1475. 12 .HEX 
  1476. 12 256 *    7 16 * +  10 + .S 
  1477. DUP BINARY .   .HEX
  1478. A variable called BASE is used to keep track of the current numeric base. The words HEX , DECIMAL , and BINARY work by changing this variable.  You can change the base to anything you want. Try:  
  1479. DECIMAL 
  1480. 7 BASE ! 
  1481. 6 1 + .  
  1482. BASE @ .
  1483. You are now in base 7 .  When you fetched and printed the value of BASE, it said 10 because 7, in base 7, is 10.   
  1484. You could define a word like .HEX for any base.  What is needed is a way to temporarily set the base while a number is printed, then restore it when we are through.  Try the following word:  
  1485. : .BINARY ( N -- , print N in Binary ) 
  1486.     BASE @     ( save current base ) 
  1487.     2 BASE !   ( set to binary ) 
  1488.     SWAP .     ( print number ) 
  1489.     BASE !     ( restore base ) 
  1490. DECIMAL 
  1491. 22 .BINARY 
  1492. 22 .  
  1493. Answers to Problems
  1494. Logical Operators  
  1495. : LOWERCASE? ( CHAR -- FLAG , true if lowercase ) 
  1496.     DUP 123 < 
  1497.     SWAP 96 > AND 
  1498. ;
  1499.  
  1500. Flow of Control
  1501. : DEDUCT  ( n -- , subtract from account )
  1502.     ACCOUNT @   ( -- n acc )
  1503.     SWAP - DUP ACCOUNT !  ( -- acc' , update variable )
  1504.     ." Balance = $" DUP . CR  ( -- acc' )
  1505.     0<  ( are we broke? )
  1506.     IF    ." Warning!! Your account is overdrawn!" CR
  1507.     THEN
  1508. ;
  1509.  
  1510. 5 -      Intermediate Forth Tutorial
  1511.  
  1512.     Intermediate Forth Tutorial    5 -  
  1513.  
  1514.  
  1515.  
  1516.  
  1517.  
  1518. Chapter 6
  1519. Advanced Forth Tutorial
  1520. String Handling      
  1521. Since we will be doing a lot of string output, let's define a very handy word.   
  1522. : $. ( $addr -- , print string ) 
  1523.     COUNT TYPE 
  1524. " Hello" $.  
  1525. As you were experimenting with text in the last lesson, you may have noticed that your string on the PAD got overwritten.  This is because the PAD is a popular place to put text in FORTH.  If you want to keep your string intact, you will need to copy it to a safe place.  To make room for a string you can use two new words called CREATE and ALLOT.  Enter:  
  1526. CREATE MY-STRING   130 ALLOT 
  1527. CREATE defines a new word similar to the way VARIABLE does.  ALLOT will make room for 130 bytes (characters)  after MY-STRING.  We will discuss these words in detail later.  You can move a string from one location to another using $MOVE.  We will use our INPUT$ word from the previous tutorial.  Enter:  
  1528. INPUT$     ( hit return then enter a string )
  1529. MY-STRING $MOVE 
  1530. The string you entered is now stored at MY-STRING.  The PAD can now be used by other words, like " , without destroying your word.  Just to prove it, enter:  
  1531. PAD $.  
  1532. " Smash" $.  
  1533. PAD $.  
  1534. MY-STRING $.  
  1535. Comparing two strings is a common task. Enter:  
  1536. " FROG" MY-STRING $MOVE 
  1537. " TREE" MY-STRING $= .  
  1538. " FROG" MY-STRING $= .  
  1539. The word $= is useful to check for string matches.  This might find application in a security system.  Enter:  
  1540. : PASSWORD ( -- flag, check password ) 
  1541.     CR ." Enter password: " INPUT$ 
  1542.     MY-STRING $=  DUP NOT ( test ) 
  1543.     IF ." Invalid password!" 
  1544.     THEN 
  1545. PASSWORD .  
  1546. If you want to alphabetize strings, you also need to know which string is "higher". Enter:  
  1547. " AARDVARK" MY-STRING $- .  
  1548. " FROG" MY-STRING     $- .  
  1549. " ZEBRA" MY-STRING    $- .  
  1550. " frog" MY-STRING     $- .  
  1551. $- compares two strings. It is sensitive to upper and lower case.   Use TEXT=? if you want to ignore case.
  1552. If you want to append one string onto another you can do so using $APPEND . Enter:  
  1553. " tree" MY-STRING $MOVE 
  1554. "  frog" COUNT MY-STRING $APPEND 
  1555. MY-STRING $.  
  1556. The following example demonstrates Text, DO LOOPs, and LEAVE .  It is a handy word that searches for a byte, or character, and tells you its offset in a string.   
  1557. VARIABLE BOFFSET 
  1558. : SEARCHBYTE ( byte addr count -- offset | -1 ) 
  1559.     -1 BOFFSET !  ( set default answer ) 
  1560.     0 
  1561.     DO  DUP I + C@  ( get byte ) 
  1562.         ( -- byte addr byte , stack looks like this ) 
  1563.         2 PICK =    ( matches? ) 
  1564.         IF I BOFFSET ! LEAVE  ( save offset ) 
  1565.         THEN 
  1566.     LOOP    2DROP 
  1567.     BOFFSET @  ( get result ) 
  1568. ASCII t " Look a tree!" COUNT .S 
  1569. SEARCHBYTE .  
  1570. Saving Forth      
  1571. You may find that you are always INCLUDEing a certain set of files when you use JForth.  Rather than INCLUDE them each time, you can INCLUDE them once and save the compiled result in another file.  Insert your JForth disk and enter:  
  1572. DOS EXECUTE JFORTH:ASSIGNS 
  1573. INCLUDE JU:SQRT 
  1574. 49 SQRT .  
  1575. Now put in your formatted JWORK: disk from the previous tutorial and enter:
  1576. SAVE-FORTH  JWORK:SQRT4TH   ( save entire Forth in file) 
  1577. BYE     ( this leaves JForth ) 
  1578. RUN JWORK:SQRT4TH    ( enter in CLI window ) 
  1579. ( wait for it to load ) 
  1580. 49 SQRT . ( SQRT is now available immediately ) 
  1581. When you SAVE-FORTH , you also have the option of expanding the dictionary space available for use.  When JForth boots, it looks at a VARIABLE called #K that tells it how much space to allocate.  To allocate 20K more dictionary, try.   
  1582. MAP  ( see how much is there now ) 
  1583. 20 #K +! 
  1584. SAVE-FORTH JWORK:BIGGER4TH  ( may need blank disk ) 
  1585. BYE 
  1586. RUN JWORK:BIGGER4TH  ( from CLI as before ) 
  1587. MAP  ( there should be more room ) 
  1588. You may want to prepare a Forth image with your favorite tools loaded.  You can also expand the amount of USER variable space available by using #U in the same way.  See #U in the glossary for more information.   
  1589. Programming Aids      
  1590. Sometimes a program doesn't behave as expected.  This, by definition, is a 'bug'.  Luckily, with Forth you have more debugging tools at your disposal than with almost any other language.  These tools can be embedded right in the language so they are always available.  You can examine any variable or constant.  You can also execute most low level words by themselves for incremental testing.  We have included, in JForth, some of the tools that we have found handy.   
  1591. We have already used WORDS.  This causes all of the Forth words to be printed out to the screen.  You can stop output by hitting a space bar. Once it is stopped, a line of Forth can be entered.  The word listing will continue after that line finishes.  Another word that is handy is WORDS-LIKE.  If you can't remember the exact name of a word but think it had a + in it, you could enter:  
  1592. WORDS-LIKE + 
  1593. also try:  
  1594. WORDS-LIKE EMIT 
  1595. WORDS-LIKE $ 
  1596. Once you have found a word, you might want to see what the code looks like for it.  We have a special word called FILE? that tells you what file any word was loaded from.  It then asks you if you want to see the source code.  As long as the source is not in the assembly language kernel, you will be able to see it.  Enter:  
  1597. FILE? <FASTEMIT> 
  1598. Try loading in some of your code and then use FILE? on your words.  FILE? works by scanning the file for occurrences of the name.  When it finds one, it prints lines until it finds a blank line.  This has the result of also showing you examples of how the word is called if it is referenced in that file.   
  1599. If you are curious about how a word actually works, you can disassemble it using DEF.  To fully understand what you are seeing, you should study the chapter on assembly language, and the chapter on the disassembler.  Try entering:  
  1600. : ADD3 3 + ; 
  1601. DEF ADD3 
  1602. : EMITA ASCII A EMIT ; 
  1603. DEF EMITA 
  1604. (A quick note to Forth/68000 experts.  TOS is D7, which is our cache for the Top Of Stack.  DSP is A6, which is our Parameter or Data Stack Pointer.)  
  1605. The Forth Interpreter and Dictionary
  1606. This section will reveal a little of what makes Forth such a unique and powerful language.  All Forths keep a list of their defined words in something called a "dictionary".  This dictionary is what you see when you call WORDS .  When you hit a carriage return, a program called the Forth "interpreter" reads each word on that line and looks it up in the dictionary.  If it finds the word, it executes the code that is associated with it.  If it doesn't find it, it flashes the screen, then reprints the word followed by a '?'.   
  1607. You can perform this sequence of operations yourself.  Enter:  
  1608. : HI ." HELLO" CR ; 
  1609. ' HI .S 
  1610. EXECUTE 
  1611. The apostrophe is a Forth word pronounced "TICK".  It takes the word that follows it and looks it up in the dictionary.  If it finds the word, it leaves the address of that word's associated code on the stack.  That address is referred to as a "CFA", pronounced "c f a".  CFA stands for Code Field Address.  The word EXECUTE takes that address and executes it.   
  1612. If you attempt to tick a word that doesn't exist, you will get an error message.  This is a handy way of finding out whether a word is defined.
  1613. ' GADCZXW   \ gives error message
  1614. You can convert the address of the code, CFA, to the address of the name of a word, the NFA, using >NAME.  This is pronounced "to name".   
  1615. Enter:  
  1616. ' HI 
  1617. >NAME ID.  
  1618. ID. takes the address of the word's name and types the name out.  You can't use COUNT and TYPE because some extras bits are set in the count byte for internal use.   
  1619. The  behavior  of  the  word  ' varies from one dialect of Forth to another. One  of  the few ways in which JForth deviates from the Forth 83 standard is illustrated as follows:  
  1620. : SAYHI ' HI EXECUTE ; 
  1621. SAYHI 
  1622. In  most  Forths  written  before  Forth 83, and JForth, the ' in SAYHI will compile  the  CFA  of  HI  .  In a true Forth 83 system, the ' would not run until  you execute SAYHI.  SAYHI would then be followed by the word you want to  "TICK".   See  the MULTI-STANDARDS file for information on making JForth compatible with Forth 83.   
  1623. If  you  do  want  to  write  a word that "TICKS" another word, you must use [COMPILE] .  Try entering:  
  1624. : DUMPSWAP  ( -- , just dump SWAP ) 
  1625.     ' SWAP 
  1626.     >NAME 40 DUMP 
  1627. DUMPSWAP 
  1628. ( This next word is more useful ) 
  1629. : DUMPWORD  ( <name> -- , dump 40 bytes of word ) 
  1630.     [COMPILE] ' 
  1631.     >NAME 40 DUMP 
  1632. DUMPWORD SWAP 
  1633. DUMPWORD HI 
  1634. Every word in the Forth dictionary is linked to the previous word by its link field.  We can find out what is before HI by converting its NAME field to its LINK field and seeing where it points.  Enter:
  1635. ' HI   >NAME   .S   ( get NFA )
  1636. N>LINK  .S   ( get Link Field Address LFA )
  1637. @  ID.   ( get NFA that it points to and print it. )
  1638. You  may want to put these next words in a file.  They illustrate techniques for  threading  through  the  dictionary.  BACKWORDS can be used for listing words defined just prior to another word in the dictionary.  Enter:  
  1639. : LOOKBACK ( nfa1 -- nfa2 , show word, link ) 
  1640.      DUP ID. CR 
  1641.      N>LINK @  ( LFA points to previous NFA) 
  1642. : BACKWORDS  ( N <word> -- , show N previous words ) 
  1643.     20 MIN   ( do a maximum of 20 ) 
  1644.     [COMPILE] '  ( get CFA ) 
  1645.     >NAME   SWAP 0   ( convert to NFA ) 
  1646.     DO  LOOKBACK 
  1647.         DUP 0=       ( check for end) 
  1648.         IF LEAVE THEN 
  1649.     LOOP  DROP 
  1650. Include this code and test by entering:  
  1651. 10 BACKWORDS DUP 
  1652. If  you  are  interested  in experimenting more, look at the definitions for NAME> , DEFER , INLINE and MAX-INLINE .   Also look at the chapter on JForth Internals and Memory Organization.
  1653. Return Stack      
  1654. Consider the following two words:  
  1655. : BIRD  ." BIRD" ; 
  1656. : PROFOUND ." The " BIRD ."  flies!" CR ; 
  1657. PROFOUND 
  1658. The word PROFOUND calls BIRD.  We hope that when BIRD finishes, the word PROFOUND will continue to completion.  Execution must "return" to PROFOUND when BIRD finishes.  To do this the processor places the address where execution should resume on the "Return Stack." At the end of BIRD is a 68000 RTS instruction that pops that address off the Return Stack and branches there.  The word R@ can be used to examine this stack.  Let's use it to look at the return address.  Enter:  
  1659. : RLOOK  R@ . ; 
  1660. : TEST RLOOK ." Hello" CR ; 
  1661. TEST   
  1662. ' TEST 4 + >ABS .   
  1663. ' TEST 4 + EXECUTE 
  1664. DEF TEST 
  1665. The address you see printed is the address of the code that prints "Hello." This is what was to be executed after RLOOK.  The 68000 uses absolute addresses on the return stack thus you had to convert your calculated relative JForth address using >ABS.   
  1666. The return stack can be also be used for purposes other than storing return addresses.  You can temporarily store values there, with care.  The only rule is that the return stack must be restored to its original state before the word finishes.  Otherwise the 68000 will try to return to the wrong place, with unpredictable results.  Enter the following code:  
  1667. : TESTR  ( N M -- N+1 M ) 
  1668.     >R   ( save M on return stack ) 
  1669.     1+   ( increment N ) 
  1670.     R>   ( get M back from return stack ) 
  1671. ;   
  1672. The word >R , pronounced "to r", moves the top of the data stack to the return stack.  The word R> , pronounced "r from", moves data back from the return stack to the data stack.  There must always be an equal number of calls to >R and R> in any given word or that word will return to the wrong place.  Only use R> to get numbers that YOU placed there.   
  1673. Words for manipulating the return stack are handy for avoiding excessive data stack manipulation and can result in slightly faster code.   
  1674. The previous example could have been coded using swap, but would have been slower.   
  1675. : TESTS  SWAP 1+ SWAP ;  ( slower than TESTR ) 
  1676. Look in the glossary for information on RPICK , R0 , RP@ , RP! , and RDROP .   
  1677. Extending the Compiler     
  1678. Words like VARIABLE and CONSTANT can be used to define new words.  For this reason they are called "defining words".   
  1679. Suppose you want to write a new defining word called INTEGER.  You can make this data structure behave just like a CONSTANT .  Although this will be redundant, it will, hopefully, illustrate the use of two important words, CREATE and DOES> .  Enter:  
  1680. : INTEGER    ( value <name> -- ) 
  1681.     CREATE    ,   ( save value in dictionary ) 
  1682.     DOES>     @   ( fetch when executed ) 
  1683. 173 INTEGER MYINT     ( execute CREATE code ) 
  1684. MYINT .               ( execute DOES> code ) 
  1685. A word like INTEGER has two main parts.  The first part is the code between CREATE and DOES> .  This code executes when the defining word is executed, such as when MYINT is defined in the preceding example.  In this case the value on the stack is saved as part of MYINT.  The comma takes what is on the stack and saves it in the dictionary.   
  1686. The second part is the code that between DOES> and ';' .  This describes what the newly defined word will  do when executed.  The address of a data area called the "BODY", or "PFA", is passed to the DOES> code.  In the above example, the @ gets the value that was saved in MYINT at definition time.   
  1687. In this next example, CREATE DOES> is used to describe a new kind of word called a SPEAKER.  A SPEAKER is given a phrase to say whenever it is referenced.  Enter the following code.  (Remember the text in parentheses are comments and need not be entered.)  
  1688. : SPEAKER    ( $string <name> -- ) 
  1689.     CREATE  HERE $MOVE    ( save string in dictionary ) 
  1690.       HERE C@ ALLOT ALIGN  ( adjust DP ) 
  1691.     DOES>   COUNT TYPE CR 
  1692. " Billions and billions!" SPEAKER CARL 
  1693. " Four score!" SPEAKER ABE  ( execute CREATE code ) 
  1694. CARL      ( execute DOES> code ) 
  1695. ABE 
  1696. The DP that was referred to was the dictionary pointer.  It is the address of where new code will be compiled, and should be left at an even location.   
  1697. For another example of the use of CREATE DOES> , see the file JU:VALUE.   
  1698. Earlier in the tutorial, we described the Forth interpreter as taking words from the input stream and executing them.  This is clearly not the case when a new word is being compiled.  When the Forth interpreter finds a colon, it switches to a different state, known as "compile mode".  As words are input, instead of being immediately executed, they are compiled into whatever word is being defined.  Now you obviously need a way to get out of this state and back to "interpet mode" at the end of a word.  To accomplish this, Forth has what are called IMMEDIATE words that are executed immediately, even in compile mode.  Semicolon, ';', is one such word. Semicolon finishes the definition of a word and switches the state back to interpret mode.   
  1699. The state of the interpreter is stored in a VARIABLE called, appropriately enough, STATE.  Enter:  
  1700. STATE @ .  
  1701. Since you are in interpret mode, you should see a 0.  Let's make our own IMMEDIATE word so that we can spy on STATE in the middle of compiling. Enter:  
  1702. : STATE.PEEK  ( -- , show state ) 
  1703.     ." State = " STATE @ . CR 
  1704. IMMEDIATE ( Makes last word IMMEDIATE. ) 
  1705. STATE.PEEK 
  1706. : FOO STATE.PEEK  ." Hello." CR ; 
  1707. Forth has two other words which can change STATE.  They allow you to switch back temporarily to interpret mode in the middle of a definition.  Enter:  
  1708. : BYTE.MASK    ( n -- byte ) 
  1709.     STATE.PEEK 
  1710.     [ HEX STATE.PEEK ]  FF AND   [ DECIMAL ] 
  1711. The left bracket sets STATE to 0 so that the following words are executed immediately.  The right bracket sets STATE back to TRUE so that compilation can continue.  This can be useful if you want to do a complex calculation at compile time instead of execution time.  Compare the following two ways of defining the same word:  
  1712. : DAYS2SECS    ( #days -- #seconds ) 
  1713.     24 * 60 * 60 * 
  1714. DEF DAYS2SECS 
  1715. ( or ) 
  1716. : DAYS2SECS    ( #days -- #seconds ) 
  1717.     [ 24 60 * 60 * ] LITERAL ( calculate factor ) 
  1718.     *   ( only one multiply at compile time ) 
  1719. DEF DAYS2SECS 
  1720. In the second case, the calculation of a single multiplication factor is done at compile time.  The word LITERAL is used to compile that value into the dictionary as a constant.  The use of this technique can result in faster code.  The second word is equivalent to:  
  1721. : DAYS2SECS    86400 * ; 
  1722. If IMMEDIATE words always execute immediately whenever referenced, then how can one compile a call to an IMMEDIATE word? You can do this with [COMPILE] which you saw used with ' earlier.  [COMPILE] will cause the next word to be compiled instead of executed.  Suppose you wanted to write a word that had LITERAL compiled within it.  Enter:  
  1723. VARIABLE MCOUNT 
  1724. 10 MCOUNT ! 
  1725. : NEXTNUM  ( -- , Compile number and increment. ) 
  1726.     MCOUNT @ DUP ." MCOUNT = " . CR 
  1727.     [COMPILE] LITERAL   ( don't execute LITERAL yet) 
  1728.     1 MCOUNT +! 
  1729. IMMEDIATE 
  1730. : FOO  NEXTNUM + ;   ( 10 + ) ( execute LITERAL now ) 
  1731. : GOO  NEXTNUM + ;   ( 11 + ) 
  1732. 5 FOO .  
  1733. 5 GOO .  
  1734. 5 FOO .  
  1735. An associated word is COMPILE.  Suppose we wanted to make a compiling word similar to the one above.  Enter:  
  1736. : +MC ( -- , Compile number and add ) 
  1737.     [COMPILE] NEXTNUM  ( it is immediate ) 
  1738.     COMPILE + ( compile a call to + when +MC is used) 
  1739. IMMEDIATE 
  1740. : ZOO +MC ; 
  1741. 5 ZOO .  
  1742. 5 FOO .  
  1743. These words are difficult to explain.  The best way to get a feel for them is to turn on TRAPS and start experimenting.   
  1744. These techniques can be used for making new "flow of control" words.  The words IF , THEN , BEGIN , UNTIL , etc., are all IMMEDIATE words.  They must set up complex branches at compile time.  Suppose you want to make a new conditional construct that only stops looping if a key is hit.  Enter:  
  1745. : UNTIL-KEY 
  1746.     COMPILE ?TERMINAL 
  1747.     [COMPILE] UNTIL 
  1748. IMMEDIATE 
  1749. : TESTIT 
  1750.     BEGIN 
  1751.         ." BLAH BLAH" CR 
  1752.     UNTIL-KEY 
  1753. TESTIT 
  1754. We are really delving into the guts of Forth with these words.  Don't feel bad if this stuff confuses you.  It confuses me.  Luckily these techniques are only needed for extending the language.  Useful and productive lives can be led without them.   
  1755. Further Exploration      
  1756. There are a number of useful words that are part of standard Forth that were not covered in this tutorial.  Look these up in the glossary and experiment with them on your own.  You should now have the necessary skills to do so.  Some examples are:  
  1757. DEPTH    CMOVE   FILL    */    U< 
  1758. U.       FIND    TIB     .R 
  1759. I would also recommend reading the sections on Local Variables, Vocabularies, and Floating Point.  When you want to get into the Amiga internals, there is a chapter on Accessing the Amiga.  You will probably want to read the section on the demo programs.  Print these programs and study them.  They are your gateway to the Amiga's special capabilities.
  1760. 6 -      Advanced Forth Tutorial
  1761.  
  1762.     Advanced Forth Tutorial    6 -  
  1763.  
  1764.  
  1765.  
  1766.  
  1767.  
  1768. Chapter 7
  1769. Clone - The JForth Target Compiler  
  1770. Historically, Forth has provided a strong development environment; fast to write code in and easy to debug.  Its natural interactivity strongly contributed to both features.  However, Forth has been somewhat limited in its usefulness to the personal computer user, as it does not lend itself well to creating small standalone programs.  
  1771. The main reason is that Forth has to carry around its dictionary, and usually much of it is never used by the application.  This includes the Forth compiler itself, which is almost always disabled by vendor-provided turnkey programs!  Other language components that standalone programs often tote along without using include debugging aids, INTERPRET-related words, assemblers, disassemblers, etc.
  1772. This is where CLONE comes in, and it really is something quite unique in the Forth world!  We are very proud of CLONE and pleased to provide you this sophisticated development tool.
  1773. CLONE creates for you another executable copy of your compiled JForth program, but does so outside of the JForth dictionary.  And as it builds this "clone", it includes only the parts of JForth that are needed by your program!  This greatly reduces the size of your final program.
  1774. Also, executables created by CLONE are YOURS!  You may do with them as you wish...ROYALTY FREE!  This is an important consideration for commercial projects, as you are not allowed to distribute a JForth image (those with a dictionary) unless it has been processed by JU:TURNKEY to no longer be interactive.
  1775. How To Use Clone    
  1776. 1.  Compile the CLONE program...
  1777. a. From CLI or Shell, enter: Run Com:JForth 
  1778. b. From JForth, enter:  INCLUDE CL:TOPFILE 
  1779. Clone consumes approximately 30K of dictionary.  (We recommend SAVE-FORTHing an image with CLONE compiled so that this step need not be repeated each time.)  
  1780. 2.  Compile the program to be CLONEd.
  1781. a. You may have to increase the dictionary size (via #K) and SAVE-FORTH to have enough room.  
  1782. 3.  Enter:  CLONE <NAME>  
  1783. where:  <NAME> is the name of the main entry point of your program.  Wait for "ok".  
  1784. 4.  Enter:  SAVE-IMAGE <NAME> <FILENAME> [-s -m -icon]  
  1785. where:    <NAME> is the name of the main entry point of your program.
  1786.         <FILENAME> is the path/name of the executable file 
  1787. options: 
  1788.     -s    Include a debug symbol table for Wack 
  1789.     -m    Write a "filename.map" file (this can be big) 
  1790.     -icon    Create a "filename.info" icon file 
  1791. Notes:  
  1792. Executables created by CLONE may be launched from CLI or Workbench.   
  1793. The above mentioned main entry point should not accept parameters on the stack, but rather in the command line, like CLI commands.  These are available immediately when your program is started; the usual parsing words like WORD function normally to retrieve this information; the next WORD or LWORD operation moves the next argument on the command line to HERE.   
  1794. Technical Information About Clone    
  1795. CLONE is an expert at analyzing compiled JForth code.  Given a main entry point, it derives a complete call dependency tree sufficient to rebuild a separate executable image of minimum size, including only those words necessary to support the run time environment of the main program.   
  1796. In the process, the NAME-FIELD, LINK-FIELD, and SIZE-FIELD components are also filtered out, also reducing the size of the resultant executable.  The standard JForth Demos image (loadable from the JD: directory of your release disks) shrank from about 160K, in the JForth dictionary, to less than 28K after passing through CLONE.  No demo source file was altered from the original V1.2 release.   
  1797. MINIMUM TARGET SIZE
  1798. The minimum size of a CLONEd JForth program is about 3 Kbytes.  This is the code required to support both launching from CLI and Workbench environments.  This can be verified by CLONEing the resident JForth word NOOP with the NOCONSOLE variable (described below) turned ON.   
  1799. SPECIAL NOTE ON JFORTH "STATE"...   
  1800. Since CLONE depends heavily on the resident dictionary to function as a model for the final program, the state of the JForth environment during CLONE is crucial.  For example, if you type the JForth word SLOW before CLONEing (causing JForth to use unbuffered input/output to the console window) the CLONEd program will also exhibit this behavior.   
  1801. Another example of how the state of JForth directly affects the output file is in the use of the compiler MAX-INLINE variable;  whatever its setting when the program was compiled will affect the size of the created target.   
  1802. Clone Glossary      
  1803. These words form the user interface for the CLONE program. They are usually typed at the keyboard to create your standalone program...
  1804. CLONE ( -- , <name> )  
  1805. A two-pass program which first creates a call dependency tree for <name>, then uses the tree to build a separate program image in memory, of minimum size.   
  1806. STATS ( -- )  
  1807. Prints out a status report for the previous CLONE operation.  This includes the name of each included routine, its address in both the normal dictionary and the new image, and the number of times it is referenced by other routines in the new image.  (This same information is saved in the '.map' file if the -m option is included on the CLONE command line.)
  1808. SAVE-IMAGE ( -- , <name> <filename> [<-s -m -icon>] )  
  1809. Creates an executable file on the disk for <name>, which must exist somewhere within the current call dependency tree.  Accepts optional parameters. For more details, see HOW TO USE CLONE, above.   
  1810. SHOWME ( -- , <name> )  
  1811. Once CLONE has been performed, disassembles the CLONEd code for <name>, using target-image-relative addressing.    
  1812. INITCLONE  ( -- )
  1813. Re-Initializes CLONE, freeing all CLONE-related resources and allowing another CLONE operation to be performed.  Normally done between CLONE evolutions.
  1814.  
  1815. Two words are available to your program for special "cancel" behavior (applicable only if run fromCLI or Shell):   
  1816. CANCELKEY? ( -- n1 )  
  1817. Returns an ascii C, D, E, or F if the corresponding control key has been pressed at the keyboard; 0 otherwise.  See ENABLE_CANCEL in the section "Customizing the CLONEd Image".
  1818. Prior to compiling the CLONE program, CANCELKEY? will unconditionally return 0. 
  1819. CANCELNOW? ( -- )
  1820. If ENABLE_CANCEL has been set non-zero, calls CANCELKEY? to check if CTRL-C, D, E, or F has been pressed at the keyboard.  If so, the image is exited; otherwise, no action occurs.  See ENABLE_CANCEL in the section Customizing the CLONEd Image.
  1821. Prior to compiling the CLONE program, CANCELNOW? executes NOOP.
  1822. Customizing the CLONEd Image    
  1823. Several words, mostly state variables, are available to the programmer to control CLONE's key run time behavior.   Default values are employed that satisfy most programs, but for best results, each should be set or verified just prior to a CLONE operation.  Refer ahead to the section Clone Configuration File, for an example of how this is done conveniently.  
  1824. TRACKING  ( -- addr )
  1825. This is a variable, used as a boolean.  If non-zero, CLONE will include all the normal memory and file pointer tracking mechanisms that are used in the JForth development image; this feature automatically returns still-allocated memory, and closes still-opened files and standard Amiga libraries when the image is exited, but can increase the size of the executable and affect the run-time performance of those sections of the program which are memory allocation/deallocation intensive.   
  1826. If zero, CLONE will not include any of this support, leaving the total responsibility for memory, files and libraries to the application. Well-behaved, debugged programs are always meticulous in these respects; such extra housekeeping is unnecessary (and arguably undesirable).   
  1827. The default state for TRACKING is OFF.  
  1828. NOCONSOLE  ( -- addr )
  1829. Another boolean variable, this controls whether I/O support for a normal AmigaDOS CLI window should be included.  If your program relies on the standard Forth KEY, EMIT, ?TERMINAL, and/or TYPE words (including ."), you should set this variable OFF.  This is the configuration for CLI-oriented commands like DIR, regardless of what kind of console window (RAW:, CON: or NEWCON:) is used.   
  1830. On the other hand, if your program does not directly call any of the Forth I/O routines (such as a graphics-intensive game), NOCONSOLE should be turned ON.  This will exclude the run-time code for the normal I/O primitives and yield a smaller executable.
  1831. The default state for NOCONSOLE is OFF.  
  1832. ENABLE_CANCEL  ( -- addr )
  1833. This boolean variable matters only to CLI-based programs and, when set non-zero, causes CLONEd programs to automatically exit via QUIT on the first call to KEY after  CTRL-C, D, E or F has been typed by the user.   See the description of CANCELNOW? in the Clone Glossary section
  1834. ENABLE_CANCEL must be set non-zero BEFORE CLONEing if this ability is desired in the CLONEd program.
  1835. The default state for ENABLE_CANCEL is OFF.  
  1836. RAWEXPECTECHO  ( -- addr )
  1837. Another boolean variable, used to adjust for differences in behavior between the 2 types of CLI-based Amiga windows, RAW: and CON: (also NEWCON:, after WorkBench 1.2).  Should be set ON if your program opens a RAW: window; this causes EXPECT to echo typed characters.  Characters are automatically echoed by a CON: or NEWCON: window, so for these two types, RAWEXPECTECHO should be turned OFF.   
  1838. The default state for RAWEXPECTECHO is OFF.  
  1839. IFLEAVELONG  ( -- addr )
  1840. This variable should be set ON if you expect your CLONEd image to exceed 128K, OFF otherwise.  If an image is larger than 128K it may need to use long relocatable JSRs which need four bytes instead of the normal two bytes for short register relative JSRs.  If CLONE finds that this variable needs to be set, it will abort the current CLONE operation and inform you.  To recover from this error, enter:
  1841. INITCLONE
  1842. IFLEAVELONG ON 
  1843. Then try the CLONE operation again.
  1844. The default state for IFLEAVELONG is OFF.
  1845. IFLONGBRANCH  ( -- addr )
  1846. This variable should be set ON if CLONE aborts and tells you to set it.  To recover from this error, enter:
  1847. INITCLONE
  1848. IFLONGBRANCH ON 
  1849. Then try the CLONE operation again.
  1850. The default state for IFLONGBRANCH is OFF.
  1851. STACKSIZE  ( -- addr )
  1852. This variable is examined by CLONE to determine the initial size for the DATA stack, allocated when the image is run.  Forth programs are normally conservative in the use of the data stack; 4K is usually quite sufficient.   
  1853. The default setting for STACKSIZE is 4096.  
  1854. NOTE: This should not be confused with the setting of the "stack" in the WorkBench 'info' menu command.  That parameter determines the size of the JForth return stack (AmigaDOS defaults this value to 4096, also; this satisfies most JForth programs here, too).   
  1855. DICTIONARYSIZE  ( -- addr )
  1856. This variable is examined to determine the size of the workspace at HERE in the target image.  As in most Forth memory maps, HERE returns the address where compiled code ends, and marks the first available free address of the dictionary.  Even though the concept of a dictionary does not exist in CLONEd programs, the area is commonly referenced as a scratch string area, so SAVE-IMAGE adds "DictionarySize @'" number of bytes to the code segment as a small workspace.  It should be noted that the specified area actually resides in the saved executable, so programs should allocate larger workspaces rather than using the area above HERE.   
  1857. The default setting for DICTIONARYSIZE is 256, allowing 128 bytes for PAD, and another 128 bytes below that, shared by HERE and the number formatter. This default size represents a minimum.   
  1858. INITIALIMAGESIZE  ( -- addr )
  1859. This variable becomes important when you are CLONEing with a minimum of free memory available.  Before CLONEing, if you set INITIALIMAGESIZE to slightly (1 or 2 kbytes) more than the final image size, the amount of memory needed for CLONE to complete will be reduced by as much as 50%.
  1860. For example, if your CLONEd application size normally ends up at about 33k, and your last CLONE failed due to insufficient memory, enter: 
  1861. INITCLONE  \ to free up memory and allow CLONE to re-init
  1862. DECIMAL 35 1024 * INITIALIMAGESIZE ! \ slightly more than needed
  1863. Try CLONEing again; much less memory should be needed this time.  Of course, you may be just plain too low or fragmented for this to help (if so, reboot the Amiga to unfragment).
  1864. Please note that one of the first things CLONE does is to read INITIALIMAGESIZE and try to allocate that much memory.  Therefore, if you set it to something prohibitively high, CLONE will seem to fail immediately due to insufficient memory.
  1865. By default, INITIALIMAGESIZE is set to 4096.
  1866. ERRORCLEANUP  ( -- )
  1867. An optional DEFERed word allows the programmer to specify one cleanup word that will be executed IF the CLONEd program terminates via QUIT or ABORT (usually due to a fatal error).  If used, it should return all Amiga resources that have been allocated (close files, free memory etc.), but should take care not to free something already freed.  The stack diagram for a word placed into ERRORCLEANUP should be ( -- ).
  1868. ERRORCLEANUP is not called if the application terminates normally.
  1869. By default, ERRORCLEANUP is set up to execute NOOP.  THE APPLICATION MUST SET THIS VECTOR AT RUNTIME by including a line similar to the following in its initialization code...
  1870. ' MyErrorCleanup is ErrorCleanup
  1871. USERCLEANUP  ( -- )
  1872. An optional DEFERed word allows the programmer to specify one cleanup word that will be executed when the CLONEd program terminates normally.  If used, it should return all Amiga resources that have been allocated (close files, free memory etc.), but should take care not to free something already freed.  The stack diagram for a word placed into USERCLEANUP should be ( -- ).   
  1873. USERCLEANUP is not called if the application terminates via QUIT or by ABORTing.
  1874. By default, USERCLEANUP is set up to execute NOOP.  THE APPLICATION MUST SET THIS VECTOR AT RUNTIME by including a line similar to the following in its initialization code...
  1875. ' MyUserCleanup is UserCleanup
  1876. Clone Configuration File     
  1877. One convenient, transparent method of configuring the clone variables is to include something like the following at the end of the main load file for your program:
  1878. EXISTS? clone    \ are we compiling on top of CLONE? 
  1879. .IF              \ YES, set CLONE how I want it.  
  1880.     include CLONE.CONFIG   
  1881. .THEN 
  1882. A sample CLONE.CONFIG follows:
  1883. \ Sample CLONE.CONFIG file  (set CLONE run-time behavior) 
  1884. \  
  1885. \ Keep in working directory, conditionally INCLUDE 
  1886. \ from load file 
  1887.  
  1888. decimal 
  1889.  
  1890. Tracking      off 
  1891. NoConsole     off 
  1892. Enable_Cancel off 
  1893. RawExpectEcho off
  1894. IfLeaveLong   off 
  1895. 4096 StackSize ! 
  1896.  256 DictionarySize !
  1897. 4096 InitialImageSize !
  1898. ' noop is ErrorCleanUp 
  1899. ' noop is UserCleanUp 
  1900. Word Redefinitions under Clone    
  1901. Some JForth words functionally change due to the standalone nature of the targeted program.  Some are described here; see the file CL:REDEFS.F for a complete listing.   
  1902.     QUIT - terminates the image.   
  1903.     INTERPRET - a null word, does nothing.  (No Dictionary possible)  
  1904.     ?PAUSE - again, a null word...the CLI provides 'pause'.   
  1905.     WORD - preserves case, like LWORD.
  1906. Also, since there are no name fields in a CLONEd image, there can be niether dictionary nor reason to CLONE words that operate on such.   Examples of such words include FIND VOCABULARY ORDER DEF DISM WORDS VLIST, etc.  Most have been rendered ineffectual in CLONEd images, others could cause problems.  Don't worry, though.  It is actually quite hard to accidentally include these in your CLONEd program.
  1907. Note: you are not permitted to include any JForth compiler primitive or other such code generating utility or program in your standalone image, via CLONE or any other method or tool.  This includes words such as CFA, CREATE : ASM CODE etc.  Actually, these have been specifically written to not be CLONE-compatible, so they will not function correctly in a standalone image anyway.
  1908. How To Be Clone Compatible   
  1909. Programs destined to be CLONEd should follow these guidelines:  
  1910. ODE
  1911. An ODE program that is to be cloned must call OB.INIT at the beginning to set up the object stack and to initialize the dynamic object tracking.   It must also load the file JO:CLONE_SUPPORT if not already loaded.  See the chapter on ODE for more information.
  1912. Use Supported Data Structures
  1913. Use the system tools wherever possible. VARIABLE, ARRAY, CREATE, and DOES> are all supported data structures that will be faithfully reproduced in the final image both in data content and functionality.   
  1914. The DEFER and GLOBAL-DEFER words are the only currently supported means of vectoring execution.  An example CLONE-able execution array is provided below.   
  1915. Runtime Initialization of Data-Storage Elements which contain Addresses
  1916. CLONE will automatically relocate the contents of DEFERed and GLOBAL-DEFERed words, as well as compiled address references created with  ' <pronounced tick> or ALITERAL.  Use of these tools insures CLONE-compatibility.
  1917. Similarly, the addresses returned by CREATE-DOES> children (such as VARIABLEs or ARRAYs) will also reflect the new addresses of their data in the CLONEd image, however, the contents of their data area will be unmodified (since they often do not contain addresses).  This means that if you save addresses in such elements, your program must initialize them when it runs, before using them.  This is accomplished simply by compiling in a statement like the following (assuming a VARIABLE is being used):
  1918. ' MyWord MyVariable !  \ initialize MyVariable to point to MyWord's CFA
  1919. For more example code, see the sample execution array later in this document.
  1920. Do not assign addresses as CONSTANTs.  CONSTANT values are not changeable and therefore can't be re-initialized later by your program.  Of course, if the address can never change (such as the address of a hardware device), then use of CONSTANT is appropriate as CLONE should not relocate them.
  1921. All STRUCT elements are considered by CLONE to be data-storage and those that hold addresses (even if defined as APTRs) should be initialized by the program.
  1922. Assembly Code
  1923. Be especially careful when using either assembler format when writing CLONE-compatible programs; the address generation problem noted above is easy to create.  Always use the function as would the compiler to generate its CFA or data address at run time.  For example, if you want to load the relative address of a variable called MYVARIABLE  into A0:
  1924. WRONG, MyVariable's data addr is built at "assembly-time" and "hard-coded"...
  1925. ( RPN Example )
  1926.     MyVariable #   ar0 an   long   move
  1927. ( Forward ASM example )
  1928.     move.l  #[MyVariable],a0
  1929. CORRECT, 'MyVariable' is "asked" at run-time for its addr, then moved to a0..
  1930. ( RPN Example )
  1931.     ] MyVariable [              \ pushes tos, puts addr in tos
  1932.      tos dn   0ar an  move       \ move it to A0
  1933.      dsp a@+  tos dn  move       \ restore original TOS
  1934. ( Forward ASM example )
  1935.     callcfa  MyVariable          \ pushes TOS, puts addr into TOS
  1936.     move.l   tos,a0              \ move it to A0
  1937.     move.l   (dsp)+,tos          \ restore original TOS
  1938. Since the compiler is temporarily invoked to build the reference to MYVARIABLE, CLONE will later be able to relocate that code segment.
  1939. Run Time Initialized Example Execution Array
  1940. An example execution array:
  1941. 3 ARRAY EXECARRAY        \ 3 possible executable words 
  1942.  
  1943. : INIT-ARRAY   ( -- , set up addresses in exec array ) 
  1944.   ' NOOP       0 EXECARRAY !    \ put 'NOOP' cfa in 1st elmnt 
  1945.   ' OPEN.ALL   1 EXECARRAY !    \ put 'OPEN.ALL' cfa in 2nd elmnt 
  1946.   ' CLOSE.ALL  2 EXECARRAY !    \ put 'CLOSE.ALL' cfa in 3rd elmnt 
  1947.  
  1948. : EXECUTE-FROM-ARRAY  ( #element -- , fetch and execute ) 
  1949.   EXECARRAY @EXECUTE 
  1950. This program will work as long as INIT-ARRAY is called in the main program before the array is used.   
  1951. Differences Between Original and Cloned Code  
  1952. Small but distinct differences may be noted between the dictionary and CLONEd versions of programs, primarily due to optimizations that CLONE performs.   
  1953. 1. While VARIABLE references were compiled inline in JForth V1.2, the compiler in later versions will create CALLs to the VARIABLE's cfa in the normal dictionary.  CLONE, however, converts them to inline in the generated image, reclaiming the speed advantage.   
  1954. 2. All occurences of USER variables are converted to the VARIABLE data structure.  Functionally, there is no difference in JForth programs, and the VARIABLE construct is faster.   
  1955. 3. The target compiler will alter the particular manner that another function was called as appropriate based on the new  target address.  For example, if TEST1 called TEST2 via a JSR absolute in the original dictionary, CLONE will change it to a more efficient and smaller relative reference if possible in the new image.
  1956. 4. All VERIFY-LIBS error checking is stripped from calls to Amiga libraries.
  1957. 5. If the IFLONGBRANCH variable is set TRUE, all short ,8 bit, branch displacements are converted to long, 16 bit.
  1958. 7 -      Clone
  1959.  
  1960.     Clone    7 -  
  1961.  
  1962.  
  1963.  
  1964.  
  1965.  
  1966. Chapter 8
  1967. File I/O
  1968. This chapter describes the JForth words that provide a simple, complete interface to the AmigaDOS 
  1969. file routines.  A file is simply a collection of bytes that can be stored on a disk or in memory.  Any 
  1970. kind of data can be stored in a file.  The bytes may be ASCII characters as in a document or a 
  1971. program's source code.  They could also be data from an experiment or binary code for execution by 
  1972. the computer.
  1973. As you might expect, support is provided to perform the standard file operations.  These are:  
  1974. 1.  Opening a file for use and getting a "file pointer" that is used when referring to a file.
  1975. 2.  Using the file-pointer to read the data, write new data and/or reposition yourself in the file, seek.
  1976. 3.  Closing the file, again using the identifying file-pointer, when finished.   
  1977. Some additional tools have been provided to round out the stock supply of file utilities.  These may not 
  1978. be needed in a typical application.  These involve the generation of NUL terminated file names which 
  1979. Amiga DOS requires internally, and fast buffered I/O.   
  1980. Note that the Amiga OS already provides interfaces to some types of Amiga system files, such as icons 
  1981. (those that end in .info), libraries and others.  Such files are not normally accessed with these functions, 
  1982. but with the Amiga-supplied ones.
  1983. Before we get into too much detail, let's explore some of these tools in a tutorial.   
  1984. File I/O Tutorial
  1985. When entering this tutorial be sure to enter it exactly as written, especially when reading files..  
  1986. Otherwise you could overwrite memory causing a harmless but annoying crash.
  1987. Creating a Text File    
  1988. Let's create a new file.  We can store some text in the file then read it back out.  Rather than create a 
  1989. file on floppy disk, let's make one on the RAM: disk.  Enter:  
  1990. VARIABLE MYFILE 
  1991. NEW FOPEN RAM:FILE1 .S 
  1992. MYFILE ! 
  1993. We just created a NEW file called "FILE1" on the volume RAM:.  The number that was returned by 
  1994. FOPEN is a pointer to a special structure that we can use to access that file.  We don't have to worry 
  1995. about what is in that structure.  Just consider it as a unique identifier for that file.  We can have 
  1996. multiple files open and refer to each of them by their file pointer. We saved the file pointer in a 
  1997. variable called MYFILE because we will need it later.   
  1998. It is possible that your RAM: disk was full which can happen if you are low on memory. If so, FOPEN 
  1999. would have returned a ZERO for a file pointer.  It is important to check to make sure that the file 
  2000. pointer is not ZERO before proceeding.  That is why we used .S to show the pointer.  If you got a zero 
  2001. from FOPEN, try again using a formatted disk in DF1:, with a filename of "DF1:FILE1".   
  2002. Now let's write to the file.  Enter:  
  2003. MYFILE @  ( get the file pointer ) 
  2004.  " Important Information" COUNT .S 
  2005. FWRITE .
  2006. FWRITE expects a file pointer followed by an address and count.  It writes the string to the file and 
  2007. then returns the number of characters written. If there is an error, it will return a -1.   
  2008. If we are going to write more lines to the file, we should separate them with and "End Of Line" 
  2009. character.  EOL is a constant equal to the character used to separate lines in a file.  On the Amiga, this 
  2010. is an ASCII Linefeed.  If we write again to the file, the new data will go right after the previous data.  
  2011. This is because file I/O uses an imaginary cursor that points into the file. This type of I/O is called 
  2012. "sequential I/O" because bytes are read or written one after the other in sequence.  Enter:  
  2013. MYFILE @  EOL  FEMIT
  2014. FEMIT is a handy word that uses FWRITE to write a single character to a file.  We can now write 
  2015. another line to the file.   
  2016. MYFILE @  " COST = 23"  COUNT  FWRITE .
  2017. MYFILE @  EOL  FEMIT 
  2018. When we are finished with a file we should close it. Enter:  
  2019. MYFILE @  FCLOSE
  2020. We have now opened a file, written data to it, and closed it.  We can see the result of our work by 
  2021. entering in the CLI window:  
  2022. TYPE  RAM:FILE1 
  2023. or in JForth:  
  2024. TYPEFILE RAM:FILE1
  2025. Reading a Text File    
  2026. Now let's open that file, and read what we wrote.  Enter:  
  2027. FOPEN RAM:FILE1 .S 
  2028. MYFILE ! 
  2029. We don't need to say NEW because we are opening an existing file.  Now let's read the first 8 
  2030. characters from the file. Enter:  
  2031. PAD 200 ERASE  ( clear PAD ) 
  2032. MYFILE @  PAD 8  FREAD .  
  2033. PAD 8 TYPE 
  2034. We should see the number 8 printed after the FREAD which is the number of characters read.  The 
  2035. data was stored at PAD which we saw using TYPE . Let's now read the rest of the file.  Reading a file 
  2036. uses a cursor just like when writing.  We are now positioned after the 8th character and can read from 
  2037. that point.  Enter:  
  2038. MYFILE @  PAD 100 FREAD .  
  2039. Notice that the number printed was less than 100.  The number reflects the actual number of bytes 
  2040. read.  Since we reached the end of the file, we got fewer bytes than we asked for.  This is one way to 
  2041. tell when you reach the end of a file.  We can look at our data by entering:  
  2042. PAD 30 DUMP 
  2043. Now let's close our file. Enter:  
  2044. MYFILE @  FCLOSE 
  2045. JForth provides several tools that simplify reading text files.  These include READLINE and 
  2046. DOLINES which will be discussed later.   
  2047. Using Binary Data Files    
  2048. We can also use files to store numbers in the form of binary data.  In fact, anything in memory, arrays, 
  2049. structures, parts of the dictionary, whatever, can be written to a file using FWRITE.  Let's create an 
  2050. array of numbers then store them in a file.  We should put a count of how many numbers there are at 
  2051. the beginning of the file so we know how to read it later.  First let's make an array of data to use.  
  2052. Enter:  
  2053. CREATE MYDATA 123 ,  2931 ,  7 , 99712 ,  49 , 
  2054. VARIABLE NUM-ITEMS 
  2055. 5 NUM-ITEMS ! 
  2056. Now let's make a file to store this data in. Enter:  
  2057. NEW  FOPEN  RAM:BDATA .S 
  2058. MYFILE ! 
  2059. At the beginning of the file we should store the number of 4 byte data cells that will follow.  This will 
  2060. help us later when we want to read the file. Enter:  
  2061. MYFILE @  NUM-ITEMS  4  FWRITE .  
  2062. This wrote the 4 bytes at the address NUM-ITEMS to the beginning of the file.  In other words, we just 
  2063. wrote the contents of the variable NUM-ITEMS to the file.  Now let's write the data.   
  2064. MYFILE @  MYDATA  NUM-ITEMS @ CELLS  .S 
  2065. FWRITE .  
  2066. Each number in MYDATA occupies 4 bytes or 1 cell. By calling CELLS we calculate how many bytes 
  2067. the table of numbers occupies.   
  2068. Rather than close the file and reopen it, let's just reposition ourselves to the beginning and start 
  2069. reading.  The word FSEEK will move our cursor to anyplace in the file.  We can move to a location 
  2070. relative to our current position, or relative to the beginning or end.  Let's move to the beginning of the 
  2071. file.   
  2072. MYFILE @  0  OFFSET_BEGINNING FSEEK .
  2073. The number printed was our old position in the file.  (You can move zero bytes relative to your current 
  2074. position to find out where you are!) We can now read the number of data items in the file. Enter:  
  2075. 0 NUM-ITEMS !
  2076. NUM-ITEMS ?
  2077. MYFILE @  NUM-ITEMS 4 FREAD .
  2078. NUM-ITEMS ?
  2079. NUM-ITEMS now contains the number of data items in the file.  Let's read the data. Enter:  
  2080. MYFILE @  PAD  NUM-ITEMS @ CELLS FREAD .  
  2081. PAD @ .  ( print 123 ) 
  2082. PAD 8 + @ .  ( print 7 ) 
  2083. The data is now stored on the PAD.   
  2084. Sometimes, a data file can be so big that we don't want to load the whole thing into memory.  You can 
  2085. write a word that will read randomly from a given position in a file.  This word will check for errors 
  2086. when seeking. FSEEK will return a -1 if you have an error.  A common error is tryin to go outside the 
  2087. bounds of the file.  You may want to enter this example in a file for future use. Enter:  
  2088. : GRABDATA  ( item# -- item , read an item ) 
  2089. \ Calculate offset, skipping count at beginning.  
  2090.     CELLS CELL+ 
  2091. \ Position cursor in file.  
  2092.     MYFILE @  SWAP OFFSET_BEGINNING  FSEEK 
  2093.     0<  ABORT"  File Seek Failed!" 
  2094. \ Read the number.  
  2095.     MYFILE @  PAD 4 FREAD
  2096.     4 = NOT ABORT" File Read Failed!" 
  2097.     PAD @  
  2098. 0 GRABDATA .  ( print 123 , the first item is # 0 )
  2099. 3 GRABDATA .  ( print 99712 )
  2100. 70 GRABDATA .  ( should report failure )
  2101. Now close the file. Enter:  
  2102. MYFILE @  FCLOSE 
  2103. This demonstrated the use of a simple binary data file.  Very complex files, like the IFF files can also 
  2104. be accessed with these techniques.  See the JIFF:IFF_SUPPORT or JU:SHOWHUNKS for more 
  2105. examples.   
  2106. File I/O Reference     
  2107. Opening Files      
  2108. Prior to reading from or writing to a file, it must be 'opened'.  JForth provides four words concerned 
  2109. with opening files.   
  2110. FILEWORD ( <filename> -- $addr , parse file name from input )
  2111. If you have a file that has spaces in the name, then you cannot use WORD to get the filename because 
  2112. it will only get the first word up to the space.  FILEWORD will check to see if the first letter of a 
  2113. filename is a ", if so it will parse up to the next " for the end of the name.  This name can then be 
  2114. passed to words that use $FOPEN.
  2115. : TESTF  ( -- ) FILEWORD COUNT TYPE ;
  2116. TESTF  mydata
  2117. TESTF "name with spaces"  ( this will work!)
  2118. FOPEN   ( <filename> -- file-pointer | false , opens file )  
  2119. This reads the filename from the input stream using FILEWORD, opens the file and returns a pointer 
  2120. to a file control structure.   
  2121. FOPEN  DF1:DATAFILE 
  2122. If you do not specify a pathname, Amiga DOS will default to the current directory as set by the CD 
  2123. command.   
  2124. 0FOPEN ( 0name -- file-pointer | false , opens file )  
  2125. In this case the filename is a NUL terminated string passed on the stack.   
  2126. 0" DF0:THISFILE"  0FOPEN 
  2127. $FOPEN ( $name -- file-pointer | false , opens file )  
  2128. This accepts a standard Forth string, with a count byte.  You should use FILEWORD instead of word if 
  2129. you want to get a filename from input.   
  2130. " DF0:THISFILE"  $FOPEN 
  2131. If the file could not be opened, these words return false.   
  2132. Files are normally opened as existing, read/write.  This means that the file specified must exist, its 
  2133. contents will be preserved across the open, and both read and write operations are allowed.   
  2134. Another word, NEW  ( -- ), may precede the 'FOPEN' word to create a new file, or clear the contents of 
  2135. an existing file.   
  2136. The 'FOPEN' words access a variable called FILEMODE to determine the desired mode for opening.  
  2137. NEW places the value MODE_NEWFILE there, OLD replaces it with MODE_OLDFILE.  Note that, 
  2138. at the end of every 'FOPEN' operation, the mode will be reset to OLD .   
  2139. NOTE: Do NOT execute NEW unless it is immediately followed by the open' operation. It's 
  2140. UNNERVING to clear a wanted file on open, just because you executed NEW and forgot about it!  
  2141. It is important to check the results of a file being opened because errors can easily occur.  Open errors 
  2142. are  typically due to the file not being found because the name is incorrect or you are in the wrong 
  2143. directory.   
  2144. : OPENFILE ( <name> -- , open a file )  
  2145.      FOPEN  ( gets name from input stream ) 
  2146.      DUP \ save the file-pointer in a variable 
  2147.      IF   MYFILE ! 
  2148.      ELSE CR ." File could not be opened!"  QUIT 
  2149.      THEN
  2150. ;
  2151. Reading and Writing to files.   
  2152. The words supplied in JForth are a high-level interface to the AmigaDOS calls READ, WRITE, and 
  2153. SEEK.  One minor difference in their use is that all addresses passed as parameters are relative 
  2154. addresses.  They are converted to absolute (required by Amiga calls) within the function.    
  2155. Each function requires a 'file-pointer', which will have been acquired via FOPEN , 0FOPEN or 
  2156. $FOPEN .  File pointers are not considered addresses and are used just as AmigaDOS returns them; 
  2157. they are NEVER converted to relative.   
  2158. Their names and stack diagrams are as follows:  
  2159. FEMIT  ( file-pointer char -- , emits character to file )  
  2160. This will abort if an error occurs.   
  2161. FKEY  ( file-pointer -- char , gets character from file )  
  2162. This will abort if an error occurs.  It is not recommended that this be used in commercial aplications 
  2163. because it does not handles gracefully.  But it is handy.
  2164. FREAD  ( file-pointer addr cnt  -- #read | -1 )  
  2165. The FREAD and FWRITE functions are straightforward in their operation, operating on the 
  2166. specified memory and file (at its current address).  Each return the number of bytes processed, or -1 
  2167. if an error occurred.   
  2168. FWRITE ( file-pointer addr cnt  -- #written | -1 )  
  2169. FSEEK  ( file-pointer filepos mode -- prevpos  | -1 )  
  2170. The FSEEK 'mode' parameter equates directly to the AmigaDOS declared parameters 
  2171. OFFSET_BEGINNING, OFFSET_CURRENT, and OFFSET_END.  For example, to seek to the 
  2172. end-of-file minus 5 bytes:
  2173. MYFILE @  -5  OFFSET_END  FSEEK .   
  2174. These 5 calls will also set a user variable, FERROR, if appropriate.  (If you want to check FERROR, 
  2175. do so immediately after the function returns. It will be reset by the next file operation.)  
  2176. Following are various examples of reading from and writing to a file after it has been opened and the 
  2177. file-pointer stored in a VARIABLE called MYFILE.
  2178. Change the current location to the beginning of the file:   
  2179. MYFILE @  0  OFFSET_BEGINNING FSEEK  ( -- ret-code ) 
  2180. Read 100 bytes from current position, place them at PAD:  
  2181. MYFILE @  PAD  100 FREAD   ( -- ret-code ) 
  2182. Write 100 bytes from PAD to the file at its current location:
  2183. MYFILE @  PAD  100 FWRITE  ( -- ret-code ) 
  2184. Closing Files.      
  2185. The normal method of closing a file opened under JForth is:  
  2186. FCLOSE  ( file-pointer -- , return file resources to AmigaDOS )  
  2187. A normal program then, will use FOPEN when it starts, and FCLOSE at its completion.  In 
  2188. development environments, however, applications often will not finish as an error condition may 
  2189. cause it to QUIT.  In JForth, you may optionally mark your file to be automatically closed in this 
  2190. event by executing MARKFCLOSE on a duplicate of the just-opened file-pointer.  If your 
  2191. application successfully completes, you should UNMARKFCLOSE your file(s), so that they are not 
  2192. closed multiple times.   
  2193. MARKFCLOSE ( file-pointer -- , mark file to auto-close at quit )  
  2194. UNMARKFCLOSE ( file-pointer -- , remove from 'auto-close' stack )  
  2195. Example:  illustrates FOPEN, MARK and UNMARKFCLOSE and FCLOSE 
  2196. : EXAMPLE   ( -- , parses a filename from the input stream ) 
  2197.   FOPEN  ( -- file OR false )  ?dup 
  2198.   IF  dup MARKFCLOSE   ( file -- )   
  2199.               \ auto-close it at QUIT.  
  2200.       MYFILE !         ( -- )       
  2201.               \ save it in my variable 
  2202.       Do-My-Thing      ( -- )        
  2203.              \ do file processing, whatever it is  
  2204.       MYFILE @         ( file -- )   
  2205.              \ fetch the file pointer  
  2206.       dup UNMARKFCLOSE ( file -- )   
  2207.              \ remove from the auto-close stack 
  2208.       FCLOSE           ( -- )       
  2209.              \ and close it! 
  2210.   ELSE  cr ." File could not be opened!"  QUIT 
  2211.   THEN
  2212. Building AmigaDOS Filenames.     
  2213. Three words help you build null-terminated strings for AmigaDOS, but are not normally needed; 
  2214. FOPEN can usually be used to specify a file. These are handy to modify filenames algorithmically and 
  2215. resubmit them to AmigaDOS (via the 0FOPEN word).  They are:  
  2216. DOS0  ( -- addr , returns the address of the NUL-string buffer )  
  2217. >DOS  ( addr cnt -- , place string in DOS0, NUL terminated)  
  2218. +DOS  ( addr cnt -- , append this string to one already at DOS0)  
  2219. Note that >DOS and +DOS maintain a count byte usable by the JForth  string words.  For example, the 
  2220. contents of DOS0 can be typed by:  
  2221. DOS0 1- count type 
  2222. Here is an example of using these words to build a file pathname.   
  2223. : FOPEN.DATA  ( <name> -- , append suffix and open ) 
  2224.     FILEWORD COUNT >DOS 
  2225.     " .DATA" COUNT +DOS 
  2226.     DOS0  0FOPEN 
  2227. FOPEN.DATA  EXPT1  ( open "EXPT1.DATA" ) 
  2228. Sequential Virtual File Utilities    
  2229. Several words provided allow easy use of a 1024 byte virtual buffer area for file words designed to 
  2230. sequential single-character or cell-based transfers.  Using these words, a program may realize a 
  2231. significant speed improvement for certain types of file I/O.   
  2232. An application, at its start, may open a file-virtual buffer and store the resultant address in a variable.  
  2233. The buffer may be used by passing the address of the variable (not the buffer) as an argument to 
  2234. certain virtual-calls.   
  2235. Also, some JForth-provided functions (such as READLINE) are only accessible through this scheme.   
  2236. Those words dealing with virtual buffer management include:  
  2237. OPENFV       ( var-addr -- buffer-addr )   
  2238. Allocate a 1K buffer, and set the variable to its address.  Even though the buffer address is not 
  2239. normally needed by applications, it is returned.  If a zero is returned, an error occured.   
  2240. CLOSEFVREAD  ( var-addr -- )   
  2241. Deallocate the buffer being pointed to by VAR.  This buffer has only been read from.  Clears the 
  2242. variable.   
  2243. CLOSEFVWRITE ( file-pointer var-addr -- )   
  2244. Flush any leftover data to the file, deallocate the buffer and clear the variable.  (This buffer may have 
  2245. only been used for writing).   
  2246. F,    ( file var n1 -- )    
  2247. Send 'n1' (32 bits) to the next available cell in FILE via the virtual buffer stored in VAR.   
  2248. READLINE ( file var addr-addr maxcnt -- addr cnt | addr -1)
  2249. Read FILE via the buffer stored in VAR, place at ADDR, do not exceed MAXCNT characters.  
  2250. Returns 0 if an empty line, -1 if end-of-file.   
  2251. TEMPF,   ( n1 -- )  
  2252. Same as 'F,' but uses TEMPFILE and TEMPBUFF.   
  2253. As an example, observe this simple word which opens the file whose name follows in the input stream, 
  2254. then types each line to the screen until the end of file. (Note: TEMPFILE & TEMPBUFF are user 
  2255. variables that are pre-defined in JForth for such uses.)  
  2256. : LISTFILE   ( -- , eats name )  
  2257. \ types inputted FILENAME to console  
  2258.     FOPEN -dup 
  2259.     IF   TEMPFILE !    \ save file pointer 
  2260. \ allocate virtual buffer 
  2261.         TEMPBUFF OPENFV ( addr -- )
  2262.         drop                         
  2263. \ tempbuff inited by OpenFV, don't need addr 
  2264.         BEGIN
  2265.             TEMPFILE @  TEMPBUFF
  2266.             HERE 1000   READLINE 
  2267.             DUP 0 < 0=
  2268.             ( addr #read true-if-not-eof -- ) 
  2269.         WHILE  CR TYPE 
  2270.         REPEAT 2DROP 
  2271.         TEMPBUFF CLOSEFVREAD   \ deallocate the buffer 
  2272.         TEMPFILE @ FCLOSE           \ 
  2273.     ELSE cr ." Can't open "  DOS0 1- count type  quit 
  2274.     THEN cr 
  2275. DOLINES - Easy Text File Processing  
  2276. The DOLINES system provides a simple way to process text files on a line by line basis.  You can set 
  2277. a deferred word that will get called for each line of the file.  It will be passed the line as a string.  You 
  2278. can then do whatever you want with that string.  Here is an example of a program that types a file to 
  2279. the screen.   
  2280. First define a word that will process each line as it is read.   
  2281. INCLUDE? DOLINES JU:DOLINES 
  2282.  
  2283. : SHOWLINE ( $line -- , type it with line number ) 
  2284.     CR DL-LINENUM @ 5 .R 
  2285.     SPACE  $TYPE ?PAUSE 
  2286. DL-LINENUM is the line number that is maintained by DOLINES.  Now write a word that will set the 
  2287. vector and call DOLINES.   
  2288. : SHOWFILE ( <filename> -- , print file to screen ) 
  2289.     ' SHOWLINE IS DOLINE ( set deferred word ) 
  2290.     DOLINES 
  2291. SHOWFILE JU:BSORT 
  2292. SHOWFILE JU:ANSI 
  2293. Once the vector DOLINE is set, you can call DOLINES which will take a filename from the input 
  2294. stream, open the file, and pass each line to DOLINE.   
  2295. $DOLINES  ( $filename -- ) 
  2296. Same as DOLINES but takes name on stack as string.   
  2297. DL-LINENUM ( -- addr , variable containing current line number)
  2298. DL.CLOSE.FILE ( -- , close the doline file )
  2299. You should call this from the word that you set DOLINE.ERROR to.
  2300. DOLINE  ( $LINE -- , do something!?! )  
  2301. This is a deferred word that the user can set to anything they want as long as it has the same stack 
  2302. diagram.   
  2303. DOLINES ( <filename> -- , open and process file )  
  2304. DOLINE.ERROR ( -- )  
  2305. Deferred word that is called if an error is encountered while processing the file.  See 
  2306. DL.CLOSE.FILE.
  2307. 8 -      File I/O
  2308.     File I/O    8 -  
  2309.  
  2310.  
  2311.  
  2312.  
  2313. Chapter 9
  2314. Floating Point Arithmetic
  2315. Dave Sirag has graciously donated his implementation of the Forth Vendors Group Standard for use with JForth.  This standard supports numerous arithmetic and comparison operators and also provides very flexible numeric conversion tools.  Dave has also added numerous extensions that we think you will find helpful.  We at Delta Research are very grateful to Dave for his contribution.
  2316. There are two main files for the floating point code, JFLT:FLOAT.FFP and JFLT:FLOAT.DOUBLE.  The first file supports 32 bit single precision floating point using the Motorola Fast Floating Point Library.  The second file supports 64 bit double precision IEEF format floating point for when extreme accuracy is more important than speed.  The command sets between the two are essentially identical making it possible to write utilities that will work with either precision.   
  2317. Without further ado, let's load the 32 bit code and try it out.   
  2318. Floating Point Tutorial     
  2319. First we must load the appropriate Floating Point package.  I suggest starting with the single precision.  If you are asked for the workbench disk please insert it as requested.   
  2320. INCLUDE? F* JFLT:FLOAT.FFP 
  2321. If you see a message about words not being compiled INLINE, do not worry.  This just means that they could notbe compiled in the fastest possible form.  It is not harmful. See INLINE in the glossary.
  2322. Now we must initialize this system before using it.  Enter:  
  2323. FPINIT 
  2324. That will open up the appropriate libraries and install the proper floating point number conversion routines.  Now whenever we enter a number with a decimal point in it, it will be automatically converted to floating point.   
  2325. Simple Arithmetic and Output    
  2326. Let's try entering some numbers and doing some simple arithmetic.  Most of the arithmetic operators that Forth has for integers, "* + - / ABS MIN", etc.  have their floating point counterparts.  To add two floating point numbers together we simply call F+ .   
  2327. 23.5 F.  ( print a fp number ) 
  2328. 20.0 7.55 F+ F.  ( add two fp numbers ) 
  2329. 17.98 12.345 F/ F.  ( divide two fp numbers ) 
  2330. 10.0 PI F* F.  
  2331. We can also enter and display numbers in exponential notation.   
  2332. 23.7E15 E.  
  2333. 7.193E-8 ENG.  ( engineering format ) 
  2334. Engineering format always adjusts the exponent to a multiple of three. This is convenient for displaying seconds, milliseconds, and microseconds, or meters and kilometers, etc.   
  2335. We can control the display of our numbers by using the ".R" words.  If we want to display PI with 4 places after the decimal point in a field 12 characters wide, we can enter:  
  2336. PI 4 12 F.R 
  2337. 8.98 99876.3 F/  2 10 ENG.R 
  2338. Transcendental Functions      
  2339. Scientific calculations often require transcendental functions like sine and cosine.  This package assumes angles to be in Radians instead of degrees.  Radians are a special unit of angular measurement where 360 degrees (a circle) is two Pi, or roughly 6.3, radians.  Let's do some calculations.  (Don't worry! If you don't understand this stuff then you probably don't need it.)  
  2340. PI  FSIN F.  ( should be zero ) 
  2341. 45.0 DEG>RAD FCOS F.  ( approx 0.7 ) 
  2342. Notice the use of DEG>RAD to convert between degrees and radians.  RAD>DEG can be used to go the other way.   
  2343. 2.1  5.3 F** F.  ( raise 2.1 to the power of 5.3 ) 
  2344. 137.2 FLOG F.    ( log base 10 ) 
  2345. 13.72 FLOG F.  
  2346. Let's calculate the hypotenuse of a triangle.  Pythagoras' theorem tells us that the length of the hypotenuse of a right triangle is the square root of the sum of the squares of the two sides.   
  2347. : HYPOT  ( a b -- c , C = SQRT( A**2 + B**2 ) 
  2348.     FDUP F*  ( square B ) 
  2349.     FSWAP FDUP F* F+ ( square A and add ) 
  2350.     FSQRT  ( take square root ) 
  2351. 3.0 4.0 HYPOT F.  ( yep, the old 3,4,5 right triangle) 
  2352. 9.8 17.5 HYPOT F.  
  2353. Precision Independent Style     
  2354. Suppose you write an application that works for 32 bit single precision numbers.  Wouldn't it be nice if it also worked for double precision without having to change it.  By carefully using the special stack operators and storage words that Dave has written, you can do just that. The tricky part is that 32 bit numbers occupy one cell on the stack and 64 bit numbers occupy two cells.  If you have two 32 bit numbers on the stack and you want to swap them you can just use SWAP .  If you have two 64 bit numbers you have to use 2SWAP .  If you have mixed integer and floating point things get even trickier.  Luckily most of the common stack operations have been provided in a form that works no matter what precision we are using.  Enter:  
  2355. 43  29.712 NFSWAP . F.  
  2356. This version of SWAP assumes that the stack has an integer, N, and a float, F.  It is defined differently for different width floating point numbers.  For single precision it is just a normal SWAP , for double precision it uses ROT to do its work.   
  2357. We also need special words for VARIABLE  ,  ! and other width-dependent words. Enter:  
  2358. FVARIABLE FVAR-1 
  2359. 23.4 FVAR-1 F! 
  2360. FVAR-1 F@ F.  
  2361. That will work for single or double precision. Now, suppose you want an array of numbers.   
  2362. 20 FARRAY MY-FAR  ( declare array of 20 numbers ) 
  2363. ( store 9.876 into fourth location in array ) 
  2364. 9.876 4 MY-FAR F! 
  2365. Cloning Floating Point Code    
  2366. Please remember that you must initialize the system before using it. Otherwise it will crash dramatically.  Here is an example of a floating point program that will clone.   
  2367. : SHOWSINES  ( -- , display sines ) 
  2368.     FPINIT  ( Important!! ) CR 
  2369.     91 0 
  2370.     DO  I DUP 4 .R  ( show angle ) 
  2371.         FLOAT DEG>RAD ( convert i to radians ) 
  2372.         FSIN   4 9 F.R CR 
  2373.     LOOP 
  2374.     FPTERM 
  2375. Floating Point Glossary     
  2376. This glossary has been organized by function to make it easier to find the right word.   
  2377.  
  2378. Floating Point Control     
  2379. FPINIT    ( --- , initialize floating point )  
  2380. This must be called before using any floating point words or you will crash.  It opens the appropriate libraries and initializes some variables. The floating point files have AUTO.INIT words that will automatically call FPINIT if they are loaded permanently in a dictionary.   
  2381. FPTERM    ( --- , close libraries and cleanup )  
  2382.  
  2383. Arithmetic Operators
  2384. These operators are similar to the corresponding integer operators and, therefore, don't need much explanation.   
  2385. F+    ( r1 r2 --- r1+r2 )  
  2386. F-    ( r1 r2 --- r1-r2 )  
  2387. F*    ( r1 r2 --- r1*r2 )  
  2388. F/    ( r1 r2 --- r1/r2 )  
  2389. F2*   ( r --- r*2.0 )  
  2390. F2/   ( r --- r/2,0 )  
  2391. FABS  ( r --- |r| , take absolute value of R )  
  2392. FNEGATE ( r --- -r )  
  2393. FMAX  ( r1 r2 --- r1 | r2 , leave largest of r1 and r2 )  
  2394. FMIN  ( r1 r2 --- r1 | r2 , leave smallest of r1 and r2 )  
  2395.  
  2396. Result Flags      
  2397. The arithmetic operators above set a variable called FPSTAT to the value in the condition code registers after the operation.  These words examine FPSTAT and leave a flag if a given condition is true.  They can be used to determine if an overflow had occurred or if the result was zero, etc.  An overflow is what a happens when a calculation results in a number that is too big or too small for the machine.   
  2398. FEQ  ( -- flag , true if result zero )  
  2399. FLE  ( -- flag , true if result less than or equal to zero )  
  2400. FLT  ( -- flag , true if result less than zero )  
  2401. FGE  ( -- flag , true if result greater than or equal to zero )  
  2402. FGT  ( -- flag , true if result greater than zero )  
  2403. FNE  ( -- flag , true if result not equal zero )  
  2404. FVC  ( -- flag , true if result did NOT overflowed )  
  2405. FVS  ( -- flag , true if result overflowed )  
  2406.  
  2407. Transcendental Functions      
  2408. Angles are passed in radians.  Use DEG>RAD or RAD>DEG to convert if needed.   
  2409. DEG>RAD    ( r.deg -- r.rad , convert degrees to radians )  
  2410. DEG/RAD    ( --- r , constant number of degrees per radian )  
  2411. F**        ( r1 r2 --- r1**r2 , R1 to R2th power )  
  2412. FSQRT    ( r --- r**0.5 , take square root )  
  2413. FLN        ( r --- ln[r] , natural logarithm )  
  2414. FLOG    ( r --- log[r] , base 10 logarithm )  
  2415. FALOG    ( r --- 10**r , inverse logarithm )  
  2416. FALN    ( r --- e**r , inverse natural log )  
  2417. FSIN    ( r.rad --- sin[r] , take sine of R )  
  2418. FCOS    ( r.rad --- cos[r] )  
  2419. FTAN    ( r.rad --- tan[r] )  
  2420. FASIN    ( sin[r] --- r.rad , take arcsine of R )  
  2421. FACOS    ( cos[r] --- r.rad )  
  2422. FATAN    ( tan[r] --- r.rad )  
  2423. FSINH    ( r.rad --- sinh[r] , take hypersine of R )  
  2424. FCOSH    ( r.rad --- cosh[r] )  
  2425. FTANH    ( r.rad --- tanh[r] )  
  2426. FCS        ( r.rad --- sin[r] cos[r] , calc both quickly )  
  2427. FATCS    ( sin[r] cos[r]--- r.rad , four quadrant arctangent )  
  2428. This is similar to the ATAN2 function in FORTRAN  
  2429. PI        ( -- pi , constant )  
  2430. PI/2    ( -- pi/2 , constant )  
  2431. 2PI        ( -- 2pi , constant )  
  2432. RAD>DEG    ( r.rad -- r.deg , convert radians to degrees )  
  2433.  
  2434. Logical Operators      
  2435. These operators are just like their integer counterparts except they accept floating point numbers.  The following words accept two numbers.   
  2436. F=  F<  F>  F<=  F>=  F<>  ( r1 r2 -- flag )  
  2437. The following words compare a number to zero.   
  2438. F0=   F0<   F0>  F0<>  F0<=  F0>=  ( r -- flag )  
  2439. Stack Operators      
  2440. Since floating point numbers may be 32 bits or 64 bits, we need a way to manipulate them on the stack without knowing their size.  Then we can write programs that will work with either precision.   
  2441. F>R        ( r --- , push to return stack )  
  2442. FCELL+    ( n --- n' , add width of floating point number )  
  2443. This word will add the width of a floating point cell.  For single precision this would be 4+. For  double precision would be 8 +.   
  2444. FCELL-    ( n --- n' )  
  2445. FCELLS    ( n --- n' )  
  2446. FCELL/    ( n --- n' )  
  2447. FCELLU/    ( n --- n' )  
  2448. FDUP    ( r -- r r )  
  2449. FNOVER    ( r n --- r n r )  
  2450. FNSWAP    ( r n --- n r )  
  2451. FFNROT    ( r1 r2 n --- r2 n r1 )  
  2452. FNFROT    ( r1 n r2 --- n r2 r1 )  
  2453. FNNROT    ( r n1 n2 --- n1 n2 r )  
  2454. FOVER    ( r1 r2 -- r1 r2 r1 )  
  2455. FR>        ( --- r , pop from return stack )  
  2456. FROT    ( r1 r2 r3 --- r2 r3 r1 )  
  2457. FSWAP    ( r1 r2 -- r2 r1 )  
  2458. NFOVER    ( n r --- n r n )  
  2459. NFFROT    ( n r1 r2 --- r1 r2 n )  
  2460. NFNROT    ( n1 r n2 --- r n2 n1 )  
  2461. NFSWAP    ( n r --- r n )  
  2462. NNFROT    ( n1 n2 r --- n2 r n1 )  
  2463.  
  2464. Number Storage      
  2465. These words provide a precision-independent way of storing floating point numbers in memory and retrieving them.   
  2466. F!        ( r addr --- , store in memory )  
  2467. F@        ( addr --- r )  
  2468. FARRAY    ( n <name> --- , declare an array with N cells )  
  2469. FCONSTANT ( value <name> --- , declare a big enough constant )  
  2470. FVARIABLE  ( <name> --- , declare a big enough variable )  
  2471.  
  2472. Number Conversion Operators
  2473. For the following set of words, N is 32 bit for both double and single precision.
  2474. FIX        ( r --- n , round and convert to integer )  
  2475. FLOAT    ( n --- r , convert integer to float )  
  2476. INT        ( r --- n , truncate and convert to integer )  
  2477. PACK    ( d n --- r )  
  2478. UNPACK    ( r --- d n )  
  2479.  
  2480. Display Operators      
  2481. The single precision display words support 7 significant figures. Thus 1.2345678 F. will display 1.234568 .   
  2482. E.    ( r --- , display floating-point in exponential form )  
  2483. E.R    ( r places width --- , exp form display of  R )  
  2484. ENG.    ( r --- , display R in engineering exponential form )  
  2485. ENG.R    ( r places width --- , formatted engineering display )  
  2486. F>ENGTEXT  ( r --- addr count , converts fp to eng-form text )  
  2487. F>ETEXT    ( r --- addr count , converts fp to e-form text )  
  2488. F>TEXT    ( r --- addr count , converts fp to text )  
  2489. F.        ( r --- , display floating-point in decimal form )  
  2490. F.R        ( r places width -- , formatted decimal display of R)
  2491. PLACES    ( n --- , sets default number of fractional digits )  
  2492.  
  2493. Display Operators & Variables    
  2494. These variables can be used to control the display of numbers.  They are extensions to the FVG84 standard.   
  2495. DP-CHARS  ( --- addr , symbols for decimal point and comma )  
  2496. Allows other styles of display.  The characters in this are packed as two 16 bit numbers.  Here is an example of changing the decimal point and the commas.   
  2497. COMMAS 
  2498. 2.345,67 F.  ( normal ) 
  2499. ASCII ^ DP-CHARS W! 
  2500. ASCII - DP-CHARS 2+ W! 
  2501. 2.345,67 F.  
  2502. E.PLUS    ( --- addr , if true, display "E+01" rather than "E01")  
  2503. EFFLD    ( --- addr , width of fractional field for E. and ENG)
  2504. EXPSYMBOL  ( --- addr , char for "E" for E. and ENG. )  
  2505. F#BYTES    ( -- #bytes , per float = 4 for single, 8 for double)
  2506. F.ENDPOINT   ( --- addr , if true, use a point at end of F. )  
  2507. FFLD    ( --- addr , - width of fractional field for F. )  
  2508. This determines the number of places after the decimal point.  Range is 0 to 7 for single precision.   
  2509. FLD        ( --- addr , total width of field for number displays)
  2510. F.EXMAX    ( --- addr , maximum exponent for decimal F. )  
  2511. If the exponent is larger than this it will use the E. format.   
  2512. FPWARN    ( --- addr , if true, display fp warning messages )  
  2513. Number Interpreters      
  2514. Floating point numbers will always be converted using base 10 (decimal) regardless of the value of BASE.  This means no HEXADECIMAL floating point numbers.  These determine how numbers will be input.   
  2515. FLOAT.INTERPRET ( --- ,allows integer decimal, and "E" form input)
  2516. FASTFP.INTERPRET  ( --- , allows integer and decimal form input)
  2517. FIX.INTERPRET  ( --- , integer input only, '.' implies double )
  2518. FNUMBER?  ( $string -- r true | false )
  2519. Converts a string to a floating point number and true if valid.  Otherwise returns false.
  2520. NTYPE   ( --- addr , type of last number converted )
  2521. This will be set when a number is input. The values are 1 = int, 2 = fp, 0 = not number.   
  2522.  
  2523. 9 -      Floating Point Arithmetic
  2524.  
  2525.     Floating Point Arithmetic    9 -  
  2526.  
  2527.  
  2528.  
  2529.  
  2530.  
  2531. Chapter 10
  2532. Object-Oriented Development Environment (ODE)
  2533. Note: ODE was developed by Phil Burk to support HMSL, the Hierarchical Music Specification Language.  ODE was then released as a part of JForth in an effort to promote object-oriented programming.  This chapter, therefore, appears in both the JForth manual, and the HMSL manual.  When information specific to JForth or HMSL appears, it will be noted as such.
  2534. Philosophy
  2535. Object-Oriented Programming (OOP) allows you to design programs in a way that more closely matches the real world.  In the world, we are surrounded by objects. These objects can be thought of as belonging to different classes, for example pens and pencils.  These can in turn be thought as belonging to larger, more general classes such as writing implements.  In the same way, an object-oriented program involves software based objects.  If you were writing a program for an airline you would have classes such as airplanes, airports, passengers, etc.  Airplanes would have information associated with them such as flight numbers, fuel capacity, altitude, and so on.  If you wanted a particular plane to climb to a new altitude, you could send it a message telling it to climb.  It would then update its internal record of its altitude.  For programs that are not tied so closely to the physical world, you might define classes of files, tables, arrays, or plots.
  2536. Quite often, the class of object that you need is already defined.  Then you can just use it without having to define new ones.  If you need something very similar to an existing class but different, you can define a new class that inherits the desired qualities of the existing class.  The fact that classes can often be used in more than one program allows you to build up a library of classes.  This can save time when programming.  
  2537. A class defines what an object is made of and what it can do.  Once you have defined a class, you can create as many instances (objects) of that class as you want.  Objects may be thought of as intelligent data structures.  Each object knows how to manipulate its own internal data.  All objects of a given class will have the same internal structure and  will use the same methods for manipulating that data.
  2538. Existing Classes in ODE
  2539. A few classes have been defined as part of the official ODE package.  The most commonly used ones are:
  2540. OB.BARRAY  = byte array
  2541. OB.ARRAY   = long word array
  2542. OB.ELMNTS  = list of N dimensional points, can also be thought of as a 2D array.
  2543. OB.LIST    = list of single values
  2544. OB.OBJLIST = list of other objects.
  2545. Hidden Data
  2546. The organization of the data and the actual techniques used to manipulate it are hidden from users of the object.   It effectively isolates the information needed to manipulate an object inside the object itself.  This promotes a very modular structure.  The code that uses an object doesn't have to know anything about how that object was implemented.  This makes it very easy to modify how an object works without having to modify the code that uses it.  This can be a great advantage when managing large software projects.
  2547. Generic Messages
  2548. When you want an object to perform some action, you send it a message.  Examples of messages might be PRINT: or CLEAR:.  Objects "know" how to respond to messages based on methods defined for their class.
  2549. An advantage of object-oriented programming is that you can send the same message to objects of different classes.  As an example, you could send a PRINT: message to several different objects.  Each one would know how to print its contents in a meaningful form.  Some would print a table of values.  Some would only print a single value.  One advantage of this is that you don't have to memorize a differently named PRINT: function for each type of data structure.  In a traditional procedural system you would be writing words like PRINT.ARRAY and PRINT.THING for different data structures.
  2550. Another advantage is that you can write generic code.  If you have a picture containing different kinds of graphics objects, you don't have to know what they are or how to draw them.  Just send each one a DRAW: message and they will each know how to draw themselves.
  2551. Tradeoffs
  2552. The use of object-oriented programming techniques can simplify software design, speed code development, reduce many types of common errors, and improve maintainability.  When you use it for awhile, you will see why so many programmers are using these techniques in ODE and other OOP languages like C++ and Smalltalk.
  2553. I know what you're thinking now.  There must be a catch.  Well, one disadvantage with objects is that there is some extra memory and speed overhead.  The object-oriented support code does use some dictionary space.  It can also be slightly slower than traditional code.  Standard Smalltalk is quite slow because everything is an object, including every variable, constant, etc.  ODE, however, was designed for real time music applications and was, therefore, optimized for speed.  This approach is too restrictive for a Forth implementation.  ODE only makes objects out of the more complex data structures.  All ODE objects use common code that has been optimized for speed.
  2554. OOP techniques can also seem strange and confusing at first.  After using it for awhile, however, you will feel a small "click" in your head and it will all become clear.  You may even find, like I do, that it is hard to imagine writing some programs without using OOP.
  2555. All things considered, OOP techniques can be a real advantage when developing software.  I think you will find it useful and enjoyable.
  2556. Origins of OOP
  2557. The inspiration for ODE came from Smalltalk, the original object-oriented programming language developed at the Xerox Palo Alto Research Center.  In an effort to promote standardization, the syntax of ODE is similar to the syntax for both Smalltalk and NEON, an object-oriented dialect of Forth for the Macintosh.
  2558. For more information about object-oriented languages and their characteristics, see the August 1986 issue of BYTE magazine.  There is also an excellent textbook available called Smalltalk-80: The Language and Its Implementation by Goldberg and Robson.  Another good text is Object Oriented Programming by Brad J. Cox. These references and many others are in the bibliography at the end of this manual.
  2559. Terminology
  2560. Class -  A description of the data contained within an object, and the methods are used to manipulate that data.
  2561. Object -  An instance of a class.  Each object has its own data space and a pointer to its class.
  2562. Method -  A function that is associated with a particular class.  By convention, method names generally end in a colon, for example, PRINT: or ADD:.
  2563. Superclass -  The class from which a new class is derived.  All classes are derived ultimately from a root class named OBJECT .
  2564. Inheritance -   Each new class automatically has available all of the properties of its superclass.  This includes all instance variables and all methods.  The new class then adds new methods and/or instance variables.
  2565. Instance Variable -  Instance Variable, definition, ^-A data item that is contained within each object of a given class.  To access an instance variable from outside an object, you must use only that object's defined methods.  Instance variables can be hidden from other code by not providing any methods for accessing them.  Instance variables can themselves be objects.
  2566. Instantiate - To create an object from its class definition.
  2567. Turorial 1 - Creating and Using Objects
  2568. Including ODE
  2569. ODE is already compiled as part of HMSL.  JForth users can load ODE by entering:
  2570. INCLUDE? OBJECT JO:LOAD_ODE
  2571. Creating an Object, Instantiation
  2572. Creating an object is similar to creating other Forth data structures, like VARIABLE.  Enter the class name followed by the name of the object to be defined.  Let's create an instance of the integer class OB.INT named MY-INT.  Enter:
  2573. OB.INT MY-INT
  2574. Please note that this since this is a defining word, it should be used outside of colon definitions, just like VARIABLE and CONSTANT .
  2575. You have now defined an object that exists in the Forth dictionary.  If you enter the name of an object, it will return its relative address.  You can use this address if you want to pass the object as an item on the stack.  Enter:
  2576. MY-INT  .
  2577. Sending Messages
  2578. To make an object do something, you must send it a message.  For example, to put a value into this integer object, send a PUT: message to it.  The integer will know what to do.  In this case it will know to take the value at the top of the stack and store it internally..  You can then send a PRINT: message to verify that this worked.  Here is  an example:
  2579. 456 PUT: MY-INT
  2580. PRINT: MY-INT ( 456 will get printed. )
  2581. The OB.INT class is not very useful except as an example.  It was written as a simple exercise and is often used as a superclass for other classes.  When I want an INTEGER I usually use a VARIABLE or a VALUE.
  2582. Using Arrays
  2583. A more useful class of objects is the array.  To create an array of 32-bit words named MY-ARRAY, enter:
  2584. OB.ARRAY MY-ARRAY
  2585. The data for the array is stored in dynamically allocated memory that we request from the operating system.  This allows small programs to access large amounts of memory whose size can vary as needed.  To allocate memory, send a ?NEW: message to the array.  The array object will request that enough space for that much data be allocated from a pool of free memory.  To allocate room for 10 cells, enter:
  2586. 10 ?NEW: MY-ARRAY .
  2587. Since each array cell is four bytes, 10*4=40 bytes were just allocated.  If the allocation was successful, the address of the allocated memory is returned.  If the allocation fails because of insufficient free memory, it will return a zero.  You should always check to make sure that you got the memory you requested.  No matter how much memory you have installed, you can always run out of free memory.  If you are writing programs for others, remember that they may not have as much memory as you do.
  2588. Now let's see what is in our array.
  2589. PRINT: MY-ARRAY
  2590. When you printed that object, it was probably full of strange numbers.  Those are the values that just happened to be in the memory you allocated.  To clear it, enter:
  2591. CLEAR: MY-ARRAY
  2592. PRINT: MY-ARRAY
  2593. Notice that you do not have to use different messages for printing integers and arrays.  This means that there will be fewer commands to memorize.  You might try sending a CLEAR: message to your integer to see what happens.
  2594. To access individual items inside your array, you can use the messages AT: and TO: .  For example:
  2595. 98 4 TO: MY-ARRAY ( Store a 98 at item number 4)
  2596. 101 3 TO: MY-ARRAY
  2597. 0 AT: MY-ARRAY . ( Fetch and print value in cell 0, the 1st cell )
  2598. PRINT: MY-ARRAY
  2599. Finding an item in an Array
  2600. So far this looks like a pretty standard array. (See ARRAY in the main glossary for an example of a standard array.)  Because it is an object, however, it can be smarter than a standard array.  Let's ask the array to find a value inside of it.  Assuming you enterred the examples above, let's ask it to find the first occurence of 101.  Enter:
  2601. 101 INDEXOF:  MY-ARRAY .S
  2602. Notice that it returned a 3 and a -1.  The 3 is the index of the value 101 and the -1 is a TRUE value.  If it can't find the value it just returns FALSE.
  2603. 0SP   1969  INDEXOF: MY-ARRAY .S
  2604. Range Checking
  2605. A common error that can occur when programming is to use an array index that is too large for the array.  Our array has 10 items in it.  The indices run from 0 to 9.   Let's try to read past the end of our array.
  2606. 10 AT: MY-ARRAY
  2607. 123 900 TO: MY-ARRAY
  2608. ODE can check for indices that are out of range and will abort if it detects one.  Notice that it printed several things here.  The index out of range is printed first.  Then ODE dumps the object stack. (More about this later.)  The current object is the bottom one listed.  Then it prints the nature of the error.  This is especially handy when debugging.  Once you have an application thoroughly debugged, you can turn off this range checking.  One way to do this is to enter:
  2609. FALSE DO.RANGE: MY-ARRAY
  2610. 10 AT: MY-ARRAY  \ you get a number but it is garbage
  2611. Warning, do not try to see if TO: will let you over-index.  AT: is safe but over-indexing TO: can overwrite memory and cause you to crash.
  2612. Another way to turn off range checking is to enter RUN.FASTER and recompile your program.  This will affect all objects compiled.
  2613. If you forget how many items you have, you can use LIMIT:. Enter:
  2614. LIMIT: MY-ARRAY .
  2615. Freeing Memory in Array Classes
  2616. Many classes use the NEW: method to allocate memory for their use, as we have seen.  When one is finished using an object, one must DEallocate the memory.  This is done with the FREE: method.
  2617. FREE: MY-ARRAY
  2618. I recommend writing a word that frees all the objects that need to be freed.  You can then use IF.FORGOTTEN to make sure this word is called automatically if you forget the code that defines them.  Once you FORGET an object, it is too late to FREE: it..
  2619. : CLEANUP
  2620.     FREE: MY-ARRAY
  2621. ;
  2622. IF.FORGOTTEN IF.FORGOTTEN
  2623. }STUFF: and FILL:
  2624. Let's now try to stuff some specific numbers into our array.  One easy way to do this is using }STUFF:.  Enter:
  2625. STUFF{  23  987  44  2001 }STUFF: MY-ARRAY
  2626. PRINT: MY-ARRAY
  2627. Notice that }STUFF: automatically allocates memory if needed.  If you want you can call ?NEW: before }STUFF: to guarantee allocation.
  2628. To fill an entire array at once, enter:
  2629. 345 FILL: MY-ARRAY
  2630. PRINT: MY-ARRAY
  2631. Now that we are done, enter:
  2632. FREE: MY-ARRAY
  2633. Tutorial 2 - Early versus Late Binding
  2634. To Whom It May Concern,
  2635. In the previous tutorial, we sent messages to a specific object, MY-ARRAY.  This would be like sending a message to a specific person.  We would put that person's name on the message, "Dear Larry, blah blah blah".  Sometimes, however, we don't have any specific person in mind to receive the message.  If a shopkeeper goes to lunch, he or she would put a "Gone to Lunch" message on their door.  The message would then be received by anyone who happened to stand in front of that door.  Similarly, we can send a message to whatever object happens to have its address on the top of the stack.  When we write the message we may not know what object that is so we cannot use its name in the message.
  2636. The word [] (a left square bracket followed by a right square bracket pronounced "bracket bracket") can be used to send a message to an object on the stack.  ODE programmers also pronounce this as "late-bind." The following two lines are essentially equivalent.
  2637. PRINT: MY-ARRAY
  2638. MY-ARRAY PRINT: []  ( MY-ARRAY leaves its address on stack)
  2639. The first technique is called early binding and the second is called late binding.  When a word is compiled with early binding, the CFA (Code Field Address) of the method to use is determined at compile time and compiled into the dictionary.  For late binding, this process doesn't happen until run time.  Late binding is therefore slightly slower than early binding but is often required for its added functionality.  
  2640. This may sound more complicated than it really is in actual use. Late-binding is simply a technique for sending a message to an object addressed "to whom it may concern." The main difference  is that in late-binding, the object's address comes before the method, and the method is followed by the late-bind brackets.
  2641. Imagine that you wanted to define a word that would print then clear the contents of many different objects.  This could easily be done with late binding.  (You might want to put this next example in a file because we will change it later.)
  2642. : PRINT&CLEAR ( object-address -- , print then clear an object )
  2643.     DUP   ( duplicates the object address )
  2644.     PRINT: [] ( use late-binding )
  2645.     CLEAR: []
  2646. ;
  2647. MY-INT PRINT&CLEAR ( pass the address of MY-INT )
  2648. MY-ARRAY PRINT&CLEAR
  2649. Local Variables and Late Binding
  2650. A useful technique with late-binding is to use local variables to hold the address of the object.  (Please familiarize yourself with local variables before continuing.  JForth users will find them in chapter 11.  Macintosh users will find them described in the Macintosh supplement.)  Locals can help eliminate confusing stack manipulations.  As an example, you could slightly modify the above word to store the address of the object in a local variable:
  2651. : PRINT&CLEAR { obj -- , print then clear an object }
  2652.     OBJ PRINT: []
  2653.     OBJ CLEAR: []
  2654. ;
  2655. Since this technique is used so often with local variables, ODE supports an alternative syntax.  Local variables that contain an object address can be used as if they were an object.  The message is still late bound, but it is easier to read.  Here is another way to write the above word.
  2656. : PRINT&CLEAR { obj -- , print then clear an object }
  2657.     PRINT: OBJ 
  2658.     CLEAR: OBJ 
  2659. ;
  2660. This example is rather trivial.  The power of using these local variables will be more apparent when used in more complex words.
  2661. Now that we are done, don't forget to enter:
  2662. FREE: MY-ARRAY
  2663.  
  2664. Tutorial 3 - Using OB.ELMNTS
  2665. A very useful subclass of OB.ARRAY is OB.ELMNTS.  Each element of this array can have multiple values.  An example would be an array of X,Y points, or elements.  Each element would have 2 dimensions, X and Y.  In a 3 dimensional array, each element would have an X, a Y and a Z value.  The space need not be geometric.  Another 3 dimensional space could have the dimensions Time, Pitch, and Loudness.  The elements in this space could be musical notes.  Let's look at an example of an array of X,Y points.  Let's make room for 100 points with 2 dimensions. Enter:
  2666. OB.ELMNTS  XYPS  \ x,y points
  2667. 100 2 ?NEW: XYPS .  \ if zero then not enough memory!
  2668. When we printed the array, we saw that there were no points in the array yet.  Let's add some.  Enter:
  2669. 10 52 ADD: XYPS
  2670. 30 17 ADD: XYPS
  2671. 15 294 ADD: XYPS
  2672. PRINT: XYPS
  2673. ADD: is based on the notion that elements have no value until a value has been given them.  In reality, of course, every byte in a computer has a value from the moment it is turned on.  In this model, however, even though data memory has been allocated, the object is considered to be initially empty.  You can add elements one at a time by using ADD: and have it keep track of how many you have added.  You can find out how many elements have been added by using MANY: .For example:
  2674. MANY: XYPS . ( Prints '3' )
  2675. We can access the elements in the array using GET: and PUT:.  These take an index and operate on the whole element.  Let's change the value of the second point.  Remember that elements are numbered starting with zero so the second point is number 1. The first point is number 0.
  2676. 50 99 1 PUT: XYPS
  2677. PRINT: XYPS
  2678. 1 GET: XYPS .S
  2679. CR SWAP . .
  2680. If you want to access an individual number, you can use ED.TO: and ED.AT:.  The "ED" stands for element and dimension to help you remember how to pass the indices.  To change the value in element 2, dimension 1, enter:
  2681. 75 2 1 ED.TO: XYPS
  2682. PRINT: XYPS
  2683. 2 1 ED.AT: XYPS .
  2684. We can ADD: more elements to the end or we can insert elements anywhere in the middle or at the beginning.  Enter:
  2685. 63 444 1 INSERT: XYPS \ before element 1
  2686. PRINT: XYPS
  2687. We can remove an element as well.  Enter:
  2688. 0 REMOVE: XYPS
  2689. PRINT: XYPS
  2690. Another way to access the elements is sequentially.  We can get the first element using: FIRST: then continue using NEXT:.  Enter:
  2691. FIRST: XYPS SWAP . .
  2692. NEXT: XYPS SWAP . .
  2693. MANYLEFT: XYPS .  \ just one left to process
  2694. NEXT: XYPS SWAP . . \ that's the last one
  2695. If we go to far with NEXT we will get an error.  Enter:
  2696. NEXT: XYPS 
  2697. We went past the end and got an error. If we want to keep going forever we could use NEXTWRAP:.  It will wrap around back to the first element when it reaches the end.
  2698.  The read pointer can be set to a specific point or reset back to the beginning.
  2699. 1 GOTO: XYPS  \ set to read #1
  2700. NEXT: XYPS SWAP . .
  2701. WHERE: XYPS .  \ where are we now?
  2702. RESET: XYPS
  2703. NEXT: XYPS SWAP . .
  2704. If you don't want to ADD: points, you can use SET.MANY: to make it seem as if there are many points.  Enter:
  2705. 50 SET.MANY: XYPS
  2706. PRINT: XYPS
  2707. 77 0 FILL.DIM: XYPS
  2708. PRINT: XYPS
  2709. When you want to get rid of those points, use EMPTY: which sets many to zero.  (Don' t forget that you can save typing by using <UP-ARROW> to reenter PRINT: XYPS)
  2710. EMPTY: XYPS
  2711. PRINT: XYPS
  2712. 50 SET.MANY: XYPS
  2713. PRINT: XYPS
  2714. If you want to actually clear the data use CLEAR: as follows:
  2715. CLEAR: XYPS
  2716. PRINT: XYPS
  2717. 50 SET.MANY: XYPS
  2718. PRINT: XYPS
  2719. When you are done using the array, PLEASE free the memory. Enter:
  2720. FREE: XYPS
  2721. Predefined Classes
  2722. A number of predefined classes already exist in ODE.  They can be used directly, or as the superclasses for newly defined classes.  
  2723. OBJECT
  2724. The class OBJECT is the root class for all other classes.  You will probably never use it directly, however, because all of the methods described here will work for all other classes.  This is because all classes inherit this class' methods.
  2725. ADDRESS: ( -- ivars-address , address of instance variables )
  2726. .CLASS: ( -- , print the class of an object )
  2727. DUMP: ( -- , dump object's instance variables in hex )
  2728. GET.NAME: ( -- $name , get printable name. )
  2729. This name can be used for printing graphically with GR.TEXT or for writing to a file.
  2730. NAME: ( -- , print the name of the object)
  2731. This is usually used with late binding where the name is not known.  NAME: SELF is often handy in error messages.
  2732. PUT.NAME: ( $name -- , change the name of an object. )
  2733. The default name is the dictionary name.  This name is only used for error reporting and printing.  If you change the name, you must still send messages using the name in the dictionary. This is very important to remember, especially when using dynamically instantiated objects (see the discussion later in this chapter).
  2734. SPACE: ( -- nbytes , return size of instance variable space )
  2735. This does not include specially allocated memory for arrays, etc.  It does include the space required for the memory pointers, limits, etc.  This method is not used very often.
  2736. OB.INT - subclass of OBJECT
  2737. This provides a simple integer object.  Its superclass is OBJECT
  2738. CLEAR: ( -- , clears instance variables)
  2739. GET: ( -- value, returns value of integer)
  2740. PRINT: ( -- , print value )
  2741. PUT: ( value -- , sets value of integer)
  2742. +: ( n -- , add n to value of integer)
  2743. OB.BARRAY - subclass of OBJECT
  2744. This is the basic array class.  Its methods will also work for the other array classes.  The data for the array is stored in memory allocated for it by the NEW: method.  See "Using Arrays" above.  The "elements" of the array are referred to as items to avoid confusion with the term element which has special meaning for OB.ELMNTS.  The numbering of the items starts at zero.  Thus an array with ten (10) items will have items numbered from zero (0) to nine (9).
  2745. +TO: ( value index -- , add value to the indexed item )
  2746. ?NEW: ( #items -- addr | 0, allocate memory for the array )
  2747. This will automatically free any memory which has already been allocated, then allocate a new memory area.  If memory cannot be allocated, a zero will be returned.  If you run out of memory, quit from other programs or buy some more.  See FREE:.
  2748. AT: ( index -- value )
  2749. Return the value of an indexed item.
  2750. CLEAR: ( -- , sets every item to 0 )
  2751. This executes a FILL: with zero.
  2752. DATA.ADDR: ( -- data-address )
  2753. Get address of allocated memory.  This might be used on the Amiga version of HMSL, when using, for example, OB.BARRAY as an audio waveform.
  2754. DO.RANGE: ( flag -- , enable or disable range checking )
  2755. EXTEND: ( #items -- )
  2756. Extend the memory allocated. This allocates a new area of memory and copies the old data to that new area.  The old area is then deallocated.  This is useful if you run out of items in an array.  It is slow, however, so don't use it too often. 
  2757. FILL: ( value -- )
  2758. Set every item in the entire array to value.
  2759. FREE: ( -- , free the memory allocated by the NEW: method )
  2760. If you are finished using an array, use this method to deallocate its memory.  If you do not deallocate memory for arrays in this way, the computer's memory will slowly get used up. It's good programming practice to FREE: all your objects when you're finished with them (like for example, when a piece is over).
  2761. INDEXOF: ( value -- index true | false , search array for value )
  2762. LIMIT: ( -- #items , return the number of items allocated )
  2763. This is used for setting DO Ã‰ LOOP indices, checking for out-of-range conditions, etc.
  2764. NEW: ( #items -- , allocate memory for the array )
  2765. This calls ?NEW: and aborts if it returns zero.
  2766. RANGE: ( index -- , range check index )
  2767. This will abort with an error message if the index exceeds the limit of the memory allocated.  This is performed automatically but can be disabled using DO.RANGE: .
  2768. SET.WIDTH: ( #bytes -- , Set width in bytes for array item )
  2769. This allows you to have 1-, 2-, or 4-byte wide items in the array.  The value must be set before any calls to NEW: , so that the right amount of memory can be allocated.
  2770. }STUFF: ( v0 v1 v2 ... vN -- , puts values in array )
  2771. Use with STUFF{ to load an array.  If needed, NEW: will be called to make room for the values.
  2772. STUFF{  12  34  987  6  }STUFF: MY-ARRAY
  2773. TO: ( value index -- , set the indexed item to the value )
  2774. USE.DICT:  ( flag -- )
  2775. If flag is TRUE, then ?NEW: will allot space in the dictionary when called instead of allocating dynamic memory.  This allows you to initialize an array with data at compile time and save it using SAVE-FORTH.  Only store numeric values in such an array, not addresses since they will not be valid at a later time.
  2776. WIDTH: ( -- #bytes , width of a single array item )
  2777. Example of Using Arrays
  2778. Put this part in a file.
  2779. OB.BARRAY BAR1
  2780. : RAMPUP ( -- , fill with increasing even values )
  2781.     32 NEW: BAR1 ( allocate memory )
  2782.     LIMIT: BAR1 0
  2783.     DO
  2784.         I 2* ( even number )
  2785.         I TO: BAR1 ( store 2*I at Ith item )
  2786.     LOOP
  2787. ;
  2788. INCLUDE the file then test it using by entering:
  2789. BAR1 RAMPUP ( put increasing values in array )
  2790. PRINT: BAR1
  2791. 5 AT: BAR1 . ( will print 10 )
  2792. 99 AT: BAR1 ( will report an "Index Out of Range" error )
  2793. FREE: BAR1
  2794. OB.ARRAY
  2795. This class is the same as the OB.BARRAY class except that each item is as wide as a standard stack item, which in JForth and HForth is 4 bytes. Historically, this sensitivity to stack-width is important because HMSL has run on a wide variety of platforms and different versions of Forth (including 16- bit versions). The EXEC: method has been added to this class but the indexing is the same.
  2796. EXEC: ( index -- , executes CFA stored at indexed item )
  2797. This assumes that you have stored some CFAs in the array to begin with.  You may find it useful to fill such arrays with the CFA of an error handling routine.  Then put in the specific CFAs you need.  The following example shows how to get a properly handled error if you don't execute one of your specific routines:
  2798. Example of Execution Array
  2799. Put this part in a file.
  2800. : BAD.INDEX ( -- , report error )
  2801.     ." Invalid execution index." CR ABORT
  2802. ;
  2803. : HI  . " Hello" CR ;
  2804. OB.ARRAY EVENTS
  2805. : INIT.EVENTS
  2806.     16 NEW: EVENTS ( allocate space for 16 CFAs )
  2807.     'C BAD.INDEX    FILL: EVENTS ( make safe )
  2808.     'C HI    3 TO: EVENTS
  2809. ;
  2810. INCLUDE the file then test it by entering:
  2811. INIT.EVENTS
  2812. 3 EXEC: EVENTS ( executes DOTHIS )
  2813. 5 EXEC: EVENTS ( reports error )
  2814. FREE: EVENTS  ( frees memory now that we're done )
  2815. OB.ELMNTS
  2816. This class combines a two-dimensional array with the additional features of an ordered set of data.  It has OB.ARRAY as a superclass.  All of the methods that OB.ARRAY has, therefore, also apply to OB.ELMNTS.  The rows of this array are called elements.  The columns are called dimensions.  This data structure can, therefore, be thought of as an ordered set of n-tuples.  An example of this would be using OB.ELMNTS to represent X,Y,Z values.  Each element would have 3 values, one for each physical dimension, X,Y and Z.  Another example would be using an OB.ELMNTS to represent a melody.  Then each point might have a Time and a Pitch value.  The notes in this melody could be thought of as points in a 2 dimensional time/pitch space.
  2817. ?NEW: ( #elements #dimensions -- addr | 0 )
  2818. Allocates memory for the data. The default width of each value is 4 bytes.  If memory cannot be allocated a zero is returned.
  2819. ADD: ( V1 V2 V3 Ã‰ VN -- , adds an element to the end )
  2820. This adds one row, or element, to the end.  The first ADD: goes into element number 0.  The next ADD: goes into element number 1 and so on.  See the tutorial for an example.  It is veryimportant to have the right number of values on the stack when using ADD: .  If you do not have the same number of values as the object is dimensioned, then you will have stuff left over on the stack or get stack underflows.
  2821. BACKWARD: ( -- )
  2822. Advances the cursor used by NEXT: backward one position.
  2823. CHOP: ( index count -- )
  2824. Remove count elements starting at index.
  2825. CURRENT: ( -- V1 V2 V3 Ã‰ VN , element at current position )
  2826. DIMENSION: ( -- #dimensions )
  2827. Return number of dimensions declared.
  2828. DO:    ( function_cfa -- , pass each element to the function )
  2829. This is useful when you want to do something to each of the elements.  The function must "eat"  as many values as there are dimensions.  For example, let's calculate the sum of the products of a 2 dimensional elements array.
  2830. 10 2 NEW: ELM1
  2831. 2 3 ADD: ELM1
  2832. 4 5 ADD: ELM1
  2833. VARIABLE SUM-PRODS
  2834. :  *+EACH   (  a b -- , add product of a and b to SUM-PRODS )
  2835.     *  ( multiply the two values )
  2836.     SUM-PRODS +!   ( add result to variable )
  2837. ;
  2838. 0 SUM-PRODS !
  2839. 0 GET: ELM1 *+EACH   ( -- , test function outside DO: )
  2840. SUM-PRODS @ .  ( should be 6 )
  2841. 0 SUM-PRODS !
  2842. 'C *+EACH  DO: ELM1    ( pass each element to function )
  2843. SUM-PRODS @ .  ( should be 26 )
  2844. FREE: ELM1
  2845.  
  2846. DUMP.SOURCE: ( -- )
  2847. Prints ODE source code that could be used to regenerate the state of this object.  Combining this with LOGTO allows you to save the contents of an OB.ELMNTS array as source code.  This code can be reloaded using INCLUDE.  Alternatively, you could use FWRITE and DATA.ADDR: to write a binary file containing the contents of an object.  Be sure to put a header on the file that says how much to NEW: the object and how many data items and dimensions to use.
  2848. ED.AT: ( element dimension -- value , return value at e,d )
  2849. Fetches value based on its row and column address.
  2850. ED.TO: ( value element dimension -- , store value at e,d )
  2851. These two methods (ED.TO: and ED.AT: ) are critical because all of the other access methods are written using them.  If you need to define some special access methods for a new class based on OB.ELMNTS then you will probably need to use the methods ED.AT: and ED.TO: .
  2852. ED2I:  ( element dimension -- index , convert to linear index )
  2853. OB.ELMNTS are actually implemented using one dimensional arrays.  This method returns the one dimensional array index for an element dimension pair.
  2854. EMPTY:  ( -- , set number of elements to zero )
  2855. This is faster then CLEAR: because CLEAR: actually sets the allocated memory to zero.  This only sets the element counter to zero.
  2856. FILL.DIM: ( value dim# -- , fill one dimension with a value )
  2857. FIRST: ( -- V1 V2 V3 Ã‰ VN , return first element, set pointer)
  2858. FOREWARD: ( -- )
  2859. Advances the cursor used by NEXT: foreward one position.
  2860. GET: ( element -- V1 V2 V3 Ã‰ VN , fetch a given element )
  2861. Using the example for the ADD: method:
  2862. 1 GET: ELM1 .S ( will produce )
  2863.     777 888 999
  2864. GOTO: ( element# -- )
  2865. Sets the cursor used by NEXT: .
  2866. I2ED:  ( index -- element dimension , opposite of ED2I: )
  2867. I2ADDR:  ( index -- address , determine address of an item )
  2868. Calculates actual address of an item in the array.  Use with ED2I: .
  2869. INSERT: ( V1 V2 V3 Ã‰ VN element -- , inserts new element before )
  2870. The pointers are adjusted as in REMOVE: to maintain current position.
  2871. LAST: ( -- V1 V2 V3 Ã‰ VN , return last element added )
  2872. MANY: ( -- N , return number of elements added )
  2873. Sending a MANY: message to ELM1 (from the example for the ADD: method) returns a value of 2.
  2874. MANYLEFT: ( -- N , number of elements left after current )
  2875. This is handy for checking whether an array has been exhausted using NEXT: .
  2876. MAX.ELEMENTS:  ( -- max , maximum number of elements allocated )
  2877. This will be the same as the first value passed to NEW: .
  2878. NEW: ( #elements #dimensions -- )
  2879. Calls ?NEW: and aborts if zero is returned.  ?NEW: is preferred for use in applications.
  2880. NEXT: ( -- V1 V2 V3 Ã‰ VN , element at next position )
  2881. This also increments the internal pointer.   This is useful for sequential processing.  An error will occur if you attempt to go past the end of the array.  Use MANYLEFT: to see how may are left.
  2882. NEXTWRAP: ( -- V1 V2 V3 Ã‰ VN , element at next position )
  2883. This also increments the internal pointer.   This is useful for sequential processing.  When the end of the array is reached, NEXTWRAP: will automatically wrap around back to the first element.  Use WHERE: to find out where you are if need be.
  2884. PRINT: ( -- , prints out elements in a table )
  2885. PRINT.DIM: ( dim# -- , print the values of a single dimension )
  2886. PUT: ( V1 V2 V3 Ã‰ VN element -- , stores a complete element )
  2887. This stores a row without incrementing any internal pointers.  It is usually used for editing.
  2888. REMOVE: ( element -- , removes a given element )
  2889. When pointing to an element above the one that was removed, the internal pointers will be decremented so they still point to the same data.  This moves all the higher elements down to fill in the gap.
  2890. RESET: ( -- , Resets the current element pointer to 0 )
  2891. This often precedes successive calls to NEXT: .
  2892. SET.MANY: ( N -- )
  2893. Set the number of elements currently in object.  If you want to make this object act as if you have ADDed a bunch of values, you can set the number of elements it thinks it has.  You can use SET.MANY: and then use GET: and PUT: to access any element within the range you set.  For example, instead of adding elements:
  2894. OB.ELMNTS ELM-1
  2895. 20 3 NEW: ELM-1
  2896. 15 SET.MANY: ELM-1
  2897. PRINT: ELM-1    ( notice 15 elements )
  2898. FREE: ELM-1
  2899. Note that the value for SET.MANY: cannot be greater than that for which the object was NEWed.
  2900. SIZE: ( -- N , return number of individual values added )
  2901. This is the product of MANY: and DIMENSION: .
  2902. SMEAR:  ( start count -- , smear element up )
  2903. Overwrites count elements with element at start.
  2904. SPLIT:   ( start count -- , move elements up and create a split )
  2905. This is used internally by INSERT: but can be used externally.  Copies elements above and including start up by count.  This is more difficult to explain than it is to see: try it.
  2906. STRETCH: ( index count -- , dup element at index , count times )
  2907. This will "internally" duplicate a specific element in an object, count-number of times.
  2908. WHERE: ( -- element# )
  2909. Returns the cursor used by NEXT: .
  2910.  
  2911. OB.LIST
  2912. This is a one dimensional version of OB.ELMNTS.  It is handy for keeping a list of things.  It has one new method and one altered method.
  2913. NEW:  ( #elements -- , allocate memory for one dimension )
  2914. The number of dimensions is automatically one.
  2915. DELETE:   ( value -- , removes value from list )
  2916. Looks for the value in the list and removes it if found.  For example:
  2917. OB.LIST MY-LIST
  2918. 10 NEW:  MY-LIST    ( make room )
  2919. 1111 ADD: MY-LIST
  2920. 234 ADD: MY-LIST
  2921. 1988 ADD: MY-LIST
  2922. PRINT: MY-LIST   ( see all values )
  2923. 234 DELETE: MY-LIST
  2924. PRINT: MY-LIST   ( 234 now gone )
  2925. FREE: MY-LIST
  2926. OB.OBJLIST
  2927. This class is used for storing the addresses of other objects.  Its superclass is OB.LIST so all of those methods are inherited.  OBJLIST's are extremely important in ODE, where you typically have lists of various objects that you want to be able to index into, rearrange, perform operations on, and so on.
  2928. ?INSTANTIATE:  ( class_cfa #objects -- class_pfa | 0 )
  2929. Dynamically instantiate the objects and store their addresses in the objlist.  This will call ?NEW: first to make room for the object addresses.  Returns zero if it could not allocate all of them.  For more information on dynamic instantiation, see the advanced topic later in this chapter.
  2930. DEINSTANTIATE:  ( -- )
  2931. Deinstantiates all objects created using ?INSTANTIATE.  Then FREE: the objlist.
  2932. FREEALL: ( -- )
  2933. Send a FREE: message to all objects listed within.  This can be very useful in FREE:ing all objects in a list, when you might not necessarily know exactly what those objects are! Note that FREEALL: does not actually FREE: the object list itself (just use FREE: for that).
  2934. Dynamic Instantiation using OB.OBJLIST
  2935. Here is an example that uses OB.OBJLIST to dynamically instantiate 25 arrays from memory.  Put this code in a file so you can experiment with it.
  2936. OB.OBJLIST MUCHO-ARRAYS \ declare array to hold arrays!
  2937.  
  2938. :  MAKE.MUCHO-ARRAYS  ( -- error? )
  2939. \ make room for 25 arrays in the object list
  2940.     'C OB.ARRAY 25 ?INSTANTIATE: MUCHO-ARRAYS
  2941.     IF  \ yes we made them
  2942.         25 0
  2943.         DO
  2944.             I GET: MUCHO-ARRAYS  \ get Nth array
  2945.             10 OVER     ( -- array 10 array )
  2946.             NEW: []
  2947.         ( -- array , make room for 10 in each array )
  2948.             I SWAP    ( -- I array )
  2949.             FILL: []    ( -- , fill dynamic array with I )
  2950.         LOOP
  2951.         FALSE \ no error
  2952.     ELSE
  2953.         TRUE \ couldn't instantiate!!
  2954.     THEN
  2955. ;
  2956.  
  2957. : CLEANUP.MUCHO-ARRAYS ( -- )
  2958. \ free memory in all arrays in object list
  2959.     FREEALL:  MUCHO-ARRAYS
  2960.     DEINSTANTIATE: MUCHO-ARRAYS
  2961. ;
  2962. \ Automatically cleanup if file is forgotten.
  2963. IF.FORGOTTEN CLEANUP.MUCHO-ARRAYS
  2964. Now include the file, and enter:
  2965. MAKE.MUCHO-ARRAYS .
  2966. You will now have an object list, 25 long, which contains the addresses of the twenty-five arrays.  If the instantiation failed, MAKE.MUCHO-ARRAYS would return a TRUE as an error flag.
  2967. Since these arrays have no names, only addresses in MUCHO-ARRAYS, you can only reference them by indexing into the list.  This will generally involve the technique of late binding, since you will have to pass the address of the object to the method on the stack.
  2968. For example, if you wanted  to PRINT: one of the dynamically instantiated arrays, here's how you would do it:
  2969. 5 AT: MUCHO-ARRAYS  ( -- address-of-array#5 )
  2970. PRINT: []
  2971. When you are done using these arrays, you must free them and then deinstantiate them.  Enter:
  2972. CLEANUP.MUCHO-ARRAYS
  2973. Defining New Classes and Methods
  2974. New classes can be defined if the existing ones do not provide the functionality that you need.  You should first choose the closest available class to use as the superclass.  Then decide what internal instance variables each object will need.  Any methods that have not already been declared will need to be so that they will have a method index.  Do this simple by saying:
  2975. METHOD new_method:
  2976. before your class definition (where new_method: is the name of your new method). If you are just giving new functionality to an old method you will not need to declare a new name.  For example, if you modify the PRINT: method, you won't have to declare PRINT: as a method since it already been declared for other classes.  
  2977. It is generally good programming practice to use the same method name for functions that are more or less the same.  For example PRINT: for OB.INT does different things than PRINT: for OB.ARRAY, but the user only has to remember a single method name.
  2978. If you instantiate an object inside a class definition, then it will become an instance object that will exist inside every instance of the new class.  See the later example of Instance Objects.
  2979. Class Definition Glossary
  2980. The following words can be used in the definition of new classes.  It is easiest to learn them from the examples.
  2981. :CLASS ( <word> -- , declare a brand new class )
  2982. :M ( <word> -- , start the definition of a method, like : )
  2983. CLASS, ^-;;CLASS ( -- , terminates a class' definition )
  2984. ;M ( -- , terminates a methods definition )
  2985. <SUPER ( <word> -- , declare the superclass of a class )
  2986. The new class will inherit all of the instance variables and methods of the superclass.  This word is required for every class definition.  If there isn't any special existing class that you would like to inherit from then just use OBJECT .
  2987. IV.LONG ( <name> -- )
  2988. Creates a named 32 bit instance variable.
  2989. IV.SHORT ( <name> -- )
  2990. Creates a named 16 bit instance variable.
  2991. IV.BYTE ( <name> -- )
  2992. Creates a named 8 bit instance variable.
  2993. IV.BYTES ( count <name> -- )
  2994. Make room for "count" bytes in object.  The other words, (IV.LONG, IV.SHORT, IV.BYTE, etc. ) were created using BYTES.  All instance variables must be declared before any method definitions.
  2995. METHOD ( <word> -- , declare word to be a new method )
  2996. It is recommended that the method declared end in a colon to be consistent with the syntax of other object oriented languages.  Methods only need to be declared once and can then be redefined for several different classes.
  2997. It is necessary to declare a method before the class is defined because the number of methods declared determines how large to make the classes method table.  Each class has a table of CFAs, one for each declared method.  Each method is assigned an index in that table.  This technique allows for extremely fast binding between messages and method code at the expense of some memory.  ODE requires more memory for class definitions than other similar systems, but executes late binding much faster.  This is a big advantage in real time applications like games or music.  Plus memory keeps getting cheaper so why not use it.
  2998. Instance Variables
  2999. The following words are used inside method definitions to access the instance variables of an object.   When these words are executed they calculate the address of the instance variable data, then fetch that data.  The fetch will automatically be of the proper width, for example, an IV.SHORT will use W@.  In this way, different objects can have their own private copies of the data.  To store data into these instance variables you must use one of the prefix operators described below. [Technical note: The address of the current object is kept on a special stack called the object stack.  When a method starts to execute, it can be assumed that that object's address is at the top of the object stack.  The instance variables are defined in terms of their offsets from the address of that object]. 
  3000. IV=> ( value <instance_var> --, Store value in ivar )
  3001. This word will look up the width of the instance variable and use the appropriate store function, C!, W! or ! .  To fetch the value of an instance variable just give its name.  As an example, if you want to set an instance named IV-DEPTH to 200:
  3002. 200  IV=>  IV-DEPTH  ( only valid inside a method )
  3003. ." Default depth = " IV-DEPTH  .  CR
  3004. IV+> ( value <instance_var> -- , Add value to ivar )
  3005. Note: This only works on long variables, ie. those declared with IV.LONG.
  3006. IV&> ( <instance_var> -- addr , Address of ivar )
  3007. This is useful if you need an indexed instance variable or if you need to pass an instance variable's address. Generally, if you are doing a lot of indexing of instance variables, it is probably better to use instance objects.
  3008. Using SELF in Method Definitions
  3009. Sometimes, to define a new method, you will need to use other methods already defined for that class.  This creates a problem: what object do you pass the message to inside the method definition? The usual technique of METHOD: OBJECT can't work because the objects themselves haven't been defined yet, so there is no address of any object to use for the method.  Smalltalk and ODE solve this problem with two special words, SELF and SUPER .  SELF allows you to refer to whatever object is currently being defined inside a method definition for that object. For example, when you see, CLEAR: SELF inside of a method definition you know that the object currently being called will be cleared. SELF and SUPER can only be used inside a method definition. 
  3010. Warning:  methods referenced using method_name: self must already be defined.  Otherwise any previous definition of that method for that class will be used.  This is consistent with the Forth convention of not allowing forward referencing.
  3011. For example, let's define a method called DIM.SUM: for a class which is a subclass of OB.ELMNTS. DIM.SUM: will sum the values for a given dimension.  (Note that we use local variables in the method.  The '{' denotes local variables instead of a normal stack diagram.  See the JForth or HForth manual for more information on local variables.)  Enter this in a file using a text editor.
  3012. \ Declare method to be defined.
  3013. METHOD DIM.SUM:
  3014.  
  3015. \ Declare new class as a subclass of OB.ELMNTS
  3016. :CLASS  OB.NEW.ELMNTS  <SUPER OB.ELMNTS
  3017.  
  3018. :M DIM.SUM: {  dim | cursum -- sum-of-all-values }
  3019.     0 -> CURSUM
  3020.     MANY: SELF 0
  3021.     DO
  3022.         I DIM ED.AT: SELF
  3023.         +-> CURSUM
  3024.     LOOP
  3025.     CURSUM
  3026. ;M
  3027. ;CLASS
  3028. \ Now let's instantiate one and test it.
  3029. OB.NEW.ELMNTS  NELM-1
  3030. : TEST.NELM
  3031.     10 2 NEW: NELM-1
  3032.     5 20 ADD: NELM-1
  3033.     5 7 ADD: NELM-1
  3034.     ." Sum of dimension 1 = " 1 DIM.SUM: NELM-1 . CR
  3035.     FREE: NELM-1
  3036. ;
  3037. To test it, INCLUDE the file and enter:
  3038. TEST.NELM
  3039. Using SUPER and SUPER-DOOPER  in Method Definitions
  3040. SELF is used more often than SUPER.  SUPER is only needed when the new class redefines a method but you still want to access the old one.  For example, if you want a method that prints an object as previously defined but also prints out some dashes, and an item-count:
  3041. :M PRINT: ( -- , extended print )
  3042.     PRINT: SUPER
  3043.     CR ." --------------" CR
  3044.     MANY: SELF . ." items" CR
  3045. ;M
  3046. In this example, using PRINT: SELF would have resulted in a fatal recursion - you can't use a method that is currently in the midst of being defined!. 
  3047. Occasionally you won't like the way your superclass performs a method, but you like the way that superclass's superclass does.  In this situation you can use SUPER-DOOPER instead of SUPER.
  3048. :CLASS OB.STRANGE <SUPER OB.ELMNTS
  3049. :M PRINT:    ( -- )
  3050.     ." Double Print!!!" CR
  3051.     PRINT: SUPER-DOOPER ( print like an ob.array )
  3052.     ." -----------------------" CR
  3053.     PRINT: SUPER ( print like an ob.elmnts )
  3054. ;M
  3055. ;CLASS
  3056. SUPER-DOOPER is not really standard object oriented programming, it's something we added to ODE when we needed it in the implementation of HMSL, and it has proved useful ever since.
  3057. Special Methods:  INIT:
  3058. The method INIT: is automatically executed when an object is instantiated.  If you want to set default values for the instance variables, or perform any special initialization, just define an INIT: method.  You will probably want to include an INIT: SUPER to invoke any initialization that the superclass was doing.  Generally it's best to avoid doing things inside INIT: that affect the state of the operating system.  This includes allocating memory (NEW:), opening files, etc.  Otherwise you will not be able to save the INITed object in a precompiled form, for its pointers to memory and files will be invalid the next time it is run.
  3059. Example Class Definition
  3060. To clarify this, let's define a class of object that is a city.  We want to keep track of population and area.  Let's use the OB.INT class as the superclass since it already does some of what we want the new class to do.  We can use the existing instance variable in OB.INT for the population.  We will need to add a new instance variable for the area.
  3061. METHOD PUT.AREA: ( declare new methods )
  3062. METHOD GET.AREA:
  3063. METHOD CALC.DENSITY:
  3064.  
  3065. :CLASS OB.CITY <SUPER OB.INT  ( inherit properties of OB.INT )
  3066.     IV.SHORT IV-AREA ( declare 2 bytes for the area )
  3067.  
  3068. :M INIT: ( -- , Set defaults )
  3069.     INIT: SUPER ( perform initialization of superclass, important )
  3070.     1 IV=> IV-AREA ( avoid 0 divide in CALC.DENSITY: )
  3071. ;M
  3072.  
  3073. :M PUT.AREA: ( area -- , set area of city )
  3074.     IV=> IV-AREA ( store using prefix operator )
  3075. ;M
  3076.  
  3077. :M GET.AREA: ( -- area , return city's area )
  3078.     IV-AREA ( leaves value automatically )
  3079. ;M
  3080.  
  3081. :M CALC.DENSITY: ( -- density, return people per acre )
  3082.     GET: SELF GET.AREA: SELF /
  3083. ;M
  3084.  
  3085. :M PRINT: ( -- , redefine print to perform new function )
  3086.     ." The city of " NAME: SELF CR
  3087.     ." has a population of " GET: SELF . CR
  3088.     ." and an area of " GET.AREA: SELF . CR
  3089.     ." The density is " CALC.DENSITY: SELF . CR
  3090. ;M
  3091. ;CLASS ( finish class definition )
  3092.  
  3093. OB.CITY ARMPIT ( declare two instances )
  3094. OB.CITY BIGHOLE
  3095.  
  3096. 10034  PUT: ARMPIT ( set populations )
  3097. 795  PUT: BIGHOLE
  3098.  
  3099. 45  PUT.AREA: ARMPIT ( set areas )
  3100. 29  PUT.AREA: BIGHOLE
  3101.  
  3102. PRINT: ARMPIT ( print city reports as defined )
  3103. PRINT: BIGHOLE
  3104. Example of Creating a Class with Instance Objects
  3105. Lets create a subclass of OB.ELMNTS that keeps information about each of it's dimensions.  It will have an internal array with one item per dimension.  It will be sent a NEW: and FREE: message as part of the class' NEW: and FREE: method.
  3106. ( declare methods for accessing Instance Object)
  3107. METHOD PUT.DIM.DATA: 
  3108. METHOD GET.DIM.DATA:
  3109. :CLASS FOO  <SUPER OB.ELMNTS
  3110.     IV.LONG IV-FOO-FLAVOR   ( normal instance variable )
  3111.     OB.ARRAY IV-FOO-ARRAY  ( Declare Instance Object )
  3112.  
  3113. :M NEW: ( #elmnts #dimensions -- )
  3114.     TUCK NEW: SUPER    ( calls FREE: )
  3115.     NEW: IV-FOO-ARRAY  ( so NEW: this after SUPER )
  3116. ( If you reverse the order above, IV-FOO-ARRAY will get FREE:d )
  3117. ( after NEW: SUPER because NEW: SUPER calls  SELF FREE: [] )
  3118. ;M
  3119.  
  3120. :M FREE: ( -- , called by NEW: )
  3121.     FREE: SUPER
  3122.     FREE: IV-FOO-ARRAY
  3123. ;M
  3124.  
  3125. :M PUT.DIM.DATA: ( data dim -- )
  3126.     \ set associated data for dimension 
  3127.     TO: IV-FOO-ARRAY
  3128. ;M
  3129. :M GET.DIM.DATA: ( dim -- data , get associated dim data)
  3130.     AT: IV-FOO-ARRAY
  3131. ;M
  3132.  
  3133. :M PRINT:  ( -- print values and dim data )
  3134.     PRINT: SUPER
  3135.     ." Dimension values ---" CR
  3136.     PRINT: IV-FOO-ARRAY
  3137. ;M
  3138. ;CLASS
  3139.  
  3140. \ Instantiate and use a FOO
  3141. FOO MY-FOO
  3142. 20 3 NEW: MY-FOO
  3143. 11 22 33 ADD: MY-FOO
  3144. 234 345 456 ADD: MY-FOO
  3145. 77 1 PUT.DIM.DATA: MY-FOO    ( set dimension value )
  3146. PRINT: MY-FOO
  3147. FREE: MY-FOO
  3148.  
  3149. Remember, instance objects, like instance variables, can only be referenced from inside a method or a Forth word called from a method for that object!
  3150. Advanced Topics
  3151. ODE Functions
  3152. CURRENT.OBJECT    ( -- object )
  3153. Object currently being processed.  This word is handy if a method calls a function and the function needs to know which object called it  The function can then send late bound messages to the object. A lot of HMSL objects, like jobs and interpreters automatically pass their own addresses to many of their methods, so CURRENT.OBJECT is only necessary in unusual cases.
  3154. RUN.FASTER  ( -- )
  3155. Turn off some error checking for speed.  Turns off late bound class checking which ensures that you are sending messages to a real object and not some random piece of memory.  Also turns off range checking for subsequently compiled array based classes.  Only call this when you have finished debugging your program.  Recompile your aplication after calling this.
  3156. RUN.SAFER  ( -- )
  3157. Turns on error checking turned off by RUN.FASTER   Default mode for ODE.
  3158. Getting Information About Classes
  3159. There are several words that you can use to find out information about a particular class.  These are useful if you want to get the most use from a given class.
  3160. METHODS.OF    ( <class>  --  )
  3161. Show the methods supported by a class.  For example, to see what methods are supported by the OB.ELMNTS class, enter:
  3162. METHODS.OF OB.ELMNTS
  3163. INHERITANCE.OF    ( <class>  --  )
  3164. Show the superclasses of a class   To see what classes OB.ELMNTS inherited its methods and instance variables from, enter:
  3165. INHERITANCE.OF OB.ELMNTS
  3166. ALL.METHODS    ( -- )
  3167. Show all methods declared in dictionary.
  3168.  
  3169. Dynamically Allocated Objects
  3170. Sometimes you may want to create, or instantiate, an object while a program is executing.  Otherwise all objects would have to be defined at compile time.   There are two words used in dynamic instantiation:
  3171. ?INSTANTIATE ( <class> -- object-address | 0 )
  3172. This creates an object of the requested class in free memory.  The object is added to a list of dynamic objects where it can be found using 'O . It will be given the name DYNn, where nnn goes from 000 to however many you have.  You can't reference these by name since there will be no NFA (name field address) to use for the name.  You can change the name using PUT.NAME: but this is only used for printing purposes, and cannot be used for messaging.  All messages to this object must be sent using late binding, and for this you would typically retrieve the address of the object from some user created object list or array (see the example with OB.OBJLIST ).
  3173. DEINSTANIATE ( object-address -- )
  3174. Deallocate dynamically instantiated object.
  3175. Here is an example of a dynamically allocated array object.  It uses a local variable to store the object address.  Binding to a local variable is always late binding.  Notice that in this example we check to make that INSTANTIATE and ?NEW: returned address indicating success before proceding.
  3176. : DYNARRAY { newobj -- , Demo dynamic array. }
  3177.     ?INSTANTIATE OB.ARRAY \ Create dynamic object
  3178.     DUP -> NEWOBJ  \ save in local
  3179.     IF
  3180. \ Allocate data space, note use of late-binding
  3181.         12 ?NEW: NEWOBJ
  3182.         IF
  3183.             789 FILL: NEWOBJ
  3184.             PRINT: NEWOBJ
  3185.             FREE: NEWOBJ  \ Free allocated memory
  3186.         THEN
  3187.         NEWOBJ DEINSTANTIATE \ Deallocate object.
  3188.     THEN
  3189. ;
  3190. Now test this by entering:
  3191. DYNARRAY
  3192. 'O  ( <dynamic-object>  -- object-address )
  3193. Search the list of dynamically instantiated objects for the object with the matching name.
  3194.  
  3195. If you need to use an array inside of another object, you could instantiate one and store its address in an instance variable. However, you can also declare instance objects (described previously in this chapter).
  3196. Examining Instance Variables
  3197. When debugging object-oriented code, it is useful to be able to examine instance variables even if there is no method for accessing them.  To do this you can use the DUMP: method.  ODE supplies an alternative that is "technically" illegal in an object-oriented system and allows the user to reference an instance variable using techniques normally used only for C structures.  In the previous example, if you did not have a method for GET.AREA: , you could enter:
  3198. ARMPIT REL->USE ..@ IV-AREA . ( Get the area of Armpit )
  3199. Don't try this at home, kids.
  3200. Error Reporting
  3201. There is a special facility for reporting errors inside objects.  It dumps the object stack which gives a traceback of which objects were calling which.
  3202. OB.REPORT.ERROR ( $method-name $message severity -- )
  3203. The severity is either ER_WARNING , ER_RETURN , or ER_FATAL .  For fatal errors, the object stack is printed, cleared, and execution aborted.  Here is an example of detecting an out of range error in a method called DOIT:
  3204. " DOIT:"  " Input out of range"
  3205. ER_FATAL  OB.REPORT.ERROR
  3206. Inheritance
  3207. A class definition contains several things used when one class inherits instance variables and methods from another class.  The number of bytes of instance variable space is kept.  When the subclass has instance variables defined, their offset begins after the superclass's area.
  3208. A table of CFAs for the methods of a given class is kept at the end of a class definition.  Each declared method has a method index that is the same for all classes.  When a new class is defined, a table large enough to hold all of the declared methods is alloted in the dictionary.  The word <SUPER copies the CFAs from the superclass into the CFA table of the subclass.  A message sent to an object will use these CFAs unless a new method has been defined that overwrites that entry in the table.  When SUPER is used, the CFA from the superclass's table is compiled, regardless of the value in the current class CFA table.
  3209. Memory Placement for Amiga
  3210. If you create an array object that will be used by the Amiga coprocessors, then the data must be allocated in chip memory.  This can be controlled by setting a variable called MM-TYPE to MEMF_CHIP before calling NEW: .
  3211. OB.BARRAY  IMAGE-DATA
  3212. MM-TYPE @ ( Save old value )
  3213. MEMF_CHIP MM-TYPE !
  3214. 32 NEW: IMAGE-DATA ( Allocate space in CHIP RAM )
  3215. MM-TYPE !
  3216. This is done automatically for HMSL classes that need it, i.e. OB.WAVEFORM, OB.SAMPLE and OB.ENVELOPE.
  3217. Cloning ODE Programs using JForth
  3218. If you are going to Clone a JForth program that uses ODE, you MUST do the following:
  3219. 1) Compile REDEFs that are needed by Clone.  These are loaded by default if you use the file LOAD_ODE.  If not you MUST:
  3220. INCLUDE JO:CLONE_SUPPORT
  3221. 2) Do all memory allocation at Run Time.  This means you cannot call NEW: at compile time.  You must call it from a word in your program if you need it.  If you can save a program using SAVE-FORTH then you are OK as far as this requirement is concerned.
  3222. 3) Initialize the Object Stack. The pointer uses absolute addresses for speed and must be converted before running ODE.  At the beginning of your program, therefore, you must call OS.SP! or you will definitely crash.  
  3223. 4) We recommend that you compile Clone before compiling ODE but it is not required.
  3224. 5) Since name fields are not in a Cloned image, if you are going to use NAME: or PRINT: then you must give the object a name explicitly using PUT.NAME:.
  3225. Here is an example of an ODE program that will work with Clone.
  3226. INCLUDE? TASK-CLONE_SUPPORT  JO:CLONE_SUPPORT
  3227. OB.ARRAY  MY-AR1
  3228. : GOOD.ODE  ( -- simple clonable program )
  3229.     OS.SP!   ( REQUIRED!!!!! )
  3230.     10 NEW: MY-AR1   ( only call NEW: at run time )
  3231.     " TestArray" PUT.NAME: MY-AR1    ( since NFAs will be gone )
  3232.     761 FILL: MY-AR1
  3233.     PRINT: MY-AR1
  3234.     FREE: MY-AR1
  3235. ;
  3236. ( now clone it )
  3237. CLONE GOOD.ODE
  3238. SAVE-IMAGE GOOD.ODE  RAM:GOOD.ODE
  3239. ( now in the CLI, enter )
  3240. RAM:GOOD.ODE
  3241. Explanation of ODE Structures Diagram
  3242. This is a very technical discussion of how ODE is implemented and is probably more detailed than most people need to know.
  3243. A class structure contains information about how to create an object and how to implement its methods..  Please refer to the accompanying diagram when reading this section.  The first field in the class structure is the Size of an Object.  When an object is instantiated, this much room is alloted or allocated.  The second field is the Number of Methods that this class supports.  This determines how large the jump table containing method addresses is.  The next field, the Validation Code, is used to distinguish valid classes from random memory and is used for error checking when binding.  The next field is the Superclass pointer.
  3244. When a new class is defined  the following things occur.  The new class first inherits the superclass' initial object size.  As new instance variables are declared, this size is increased.  A jump table is alloted for the class that has enough entries for all of the methods declared using METHOD .  The superclass' method pointers are copied from the superclass jump table so that the new class can inherit those methods.  When new methods are defined, the entry in the jump table is overwritten.  Each declared method has a specific index which determines its offset in any class' jump table.
  3245. When an object is instantiated, space is alloted based on the Size of Object field in the class.  The first cell of the object is set with a pointer to the method jump table for the class.  Then the first method in that jump table, INIT: , is called which initializes the object.
  3246. When a message is sent to an object, the object's address is first pushed onto the "current object stack".  Then the appropriate method is looked up in the object's classes jump table and executed.  When finished, the object is popped from the object stack.  This allows nesting of object method calls.
  3247. When a method is declared using METHOD a structure is created that has an index equal to the current value of MI-NEXT.  MI-NEXT is then incremented.  This is the index for a specific method in each class' jump table.  The methods are linked using the Previous field so that the METHODS.OF word can scan a method list for a class.
  3248.         
  3249.  
  3250. 4 -      HMSL Reference Manual
  3251.  
  3252.     ODE    4 -  
  3253.  
  3254.  
  3255.  
  3256.  
  3257.  
  3258. Chapter 11
  3259. Miscellaneous Forth Tools
  3260. Memory Allocation
  3261. History
  3262. Historically, all memory allocation in traditional Forth systems has been from the available dictionary space, the same area that new definitions are added to.  While this is sometimes a preferred technique, it is often lacking as the sole source of pooled memory.   
  3263. With the advent of sophisticated operating systems such as that available on the Amiga, Forth may inherit the ability to 'request' memory from a free memory pool maintained at no burden to the application programs.   
  3264. JForth provides a rich set of operators that fully interface with the Amiga memory manager, and additionally provide capabilities specifically suited to the Forth environment.
  3265. Allocate and Free Memory.    
  3266. JForth provides two basic primitives for handling memory requests...   
  3267. ALLOCBLOCK ( type size -- memblk | FALSE )  
  3268. Allocate from other than the available dictionary, a block of memory of 'size' number of bytes.  The type may be appropriate combinations of: MEMF_PUBLIC, MEMF_CHIP, MEMF_FAST, MEMF_CLEAR and MEMF_LARGEST.  Returns false if AllocMem() failed.  Refer to the AmigaDOS ROM Kernel Manual for details on the Amiga memory map and use of the 'MEMF_' constants.  NOTE: a type=0 is default PUBLIC, FAST if available.   
  3269. FREEBLOCK   ( memblk -- )  
  3270. Frees the memory, making it available again.  If you pass the address of memory that has already been freed then the Amiga will probably crash. 
  3271. FREEVAR  ( var-addr -- )
  3272. If the contents of the variable is non-zero, then the contents is passed to FREEBLOCK then the variable is set to zero.  This is a handy word when you store the address of allocated memory in a variable.
  3273. VARIABLE MY-VAR
  3274. MEMF_CLEAR  1000 ALLOCBLOCK   \ allocate memory
  3275. DUP .  \ is it zero?
  3276. MY-VAR !  \ save address in variable
  3277. MY-VAR FREEVAR  \ now free it
  3278. The address returned from ALLOCBLOCK is a JForth relative address, and as such, it is legal to use the Forth memory access words (@, !, etc) on them.   
  3279. The programmer may allocate memory with ALLOCBLOCK, and use it as desired. When he no longer needs the area, he should call FREEBLOCK to return it for other other tasks to use.   
  3280. Note that allocated blocks will not be preserved across the SAVE-FORTH command or when CLONING.  Your program should allocate blocks and free them at run-time.  You should avoid calling ALLOCBLOCK while compiling.  For large areas that are too difficult to build at run-time (such as SINE or TRIG tables), we recommend storing them in a file, and loading them at run-time.  See the chapter on the JForth File Manager.   
  3281. Use Memory like a Stack.   
  3282. Certain words provided by JForth are available to perform automatic storage into and out of these areas.  These words maintain a 32-bit counter that is allocated along with each memory area; this counter is used to reflect the current amount stored in the memory block (when these words are used).   
  3283. FREEBYTE  ( memblk -- next-free-byte-pos )  
  3284. Returns the contents of the counter.  This counter is set to zero when the memory block is allocated.   
  3285. FREEBYTEA ( memblk -- address-of-freebyte-counter )  
  3286. This function returns the address of the 'freebyte' counter.  The programmer may make this counter available for local storage simply by not using the words that update it.  This way, he may write to his area as desired, storing into the FREEBYTE counter to save, for example, how much data is there.   
  3287. SIZEMEM   ( memblk -- allocated-size )  
  3288. Return the originally allocated size of this block of memory.   
  3289. The words that automatically update the FREEBYTE counter are concerned with utilizing the memory-block as a STACK.  These first two implement it as a simple last-in/first-out buffer:  
  3290. PUSH  ( n1 memblk -- )  
  3291. Push 'n1' on the stack at 'memblk'.   
  3292. POP   ( memblk -- n1 )  
  3293. Retrieve the last item 'pushed' on this stack.   
  3294. Note that, for efficiency reasons, error-checking has not been implemented in PUSH and POP..if there is a chance your stack could become full or empty, you should check the FREEBYTE contents and compare it with SIZEMEM before each PUSH or that it is not zero before a POP.   
  3295. The next two words also use the area as a stack, but operate somewhat differently.  Firstly, they do not expect the address of the area but a location CONTAINING the address.   
  3296. +STACK  ( n1 var-addr -- )  
  3297. Push 'n1' on the stack whose address is contained in the var-addr.  Note that if the variable holds zero, the memory-block will be allocated, and the address placed in the variable.   
  3298. -STACK  ( n1 var-addr -- )  
  3299. Search for an occurrence of 'n1' on the stack whose address in contained in the var-addr.  If found, remove the occurrence and return.  If the number of elements on the stack becomes zero during this call, the memory block is de-allocated via FREEBLOCK, and the Var-addr will be cleared.   
  3300. Note that error-checking has been implemented in +STACK and -STACK.  +STACK will automatically expand the stack memory area if necessary (and change the contents of VAR-ADDR in the process).  -STACK will deallocate the stack memory and clear VAR-ADDR if it removed the last stack item.   
  3301. Example.       
  3302. Allocate 1K of CHIP memory, accessible by anyone...   
  3303. : GET1K  ( -- memblk ) 
  3304.     MEMF_PUBLIC  MEMF_CHIP  OR     1024  
  3305.     ( -- type size ) ALLOCBLOCK ?DUP 0= 
  3306.     IF   ." Memory allocation failed!"  QUIT 
  3307.     THEN 
  3308. VARIABLE  MY-MEM 
  3309. GET1K MY-MEM !  ( allocate and save pointer ) 
  3310. We can now use this memory for any purpose.   
  3311. 2345 MY-MEM @ !  ( set first cell in block ) 
  3312. 77 MY-MEM @ 100 + ! ( set cell at offset 100 ) 
  3313. Alternatively, we can this area as a stack.  Let's push 11, 22 and 33 to 'MY-MEM'...   
  3314. 11 MY-MEM @ PUSH 
  3315. 22 MY-MEM @ PUSH 
  3316. 33 MY-MEM @ PUSH 
  3317. 765 MY-MEM @ PUSH 
  3318. MY-MEM @ POP . ( print 765 ) 
  3319. Now selectively remove the '22' ...   
  3320. 22  MY-MEM -STACK 
  3321. The MY-MEM stack now has ( -- 11 33 ) We're all done, so return what we've borrowed...   
  3322. MY-MEM @  FREEBLOCK 
  3323. Deferred Words      
  3324. The DEFER facility allows you to call a word before it is actually defined. You can then define and redefine that word without recompiling the code that calls it.  This is very useful if you are testing a word that is compiled at the beginning of a large program.  It is also useful for redefining system words that you cannot recompile, like KEY , EMIT , and FIND .   
  3325. Using DEFER to "vector" code.   
  3326. Let's look at how we can use DEFER to experiment with a word.  Enter the following at the keyboard:  
  3327. DEFER DOIT    ( create a deferred word ) 
  3328. DOIT   ( executes QUIT ) 
  3329. : USEIT  ( -- , use DOIT in a loop ) 
  3330.     8 0 DO  DOIT  LOOP 
  3331. USEIT
  3332. You will notice that nothing appears to happen when you enter DOIT or USEIT.  This is because the default action for a deferred word is QUIT.  Now let's try changing what DOIT does without recompiling USEIT .  Enter:  
  3333. : HI ." Hello" CR ; 
  3334. HI 
  3335. ' HI IS DOIT 
  3336. DOIT 
  3337. Notice that DOIT is now the same as HI.  The Forth word IS takes a CFA from the stack and places it inside the deferred word for use when it is called.  You can now enter USEIT and see that its execution has been changed without recompiling.  This process of using a word to point to another word is called "vectored execution".   
  3338. You can use WHAT'S to find out what a deferred word is defined as.  Enter:  
  3339. WHAT'S DOIT >NAME ID.
  3340. Deferred System Words     
  3341. Many JForth system words are deferred (vectored) so that you can change how they work.  This allows you to do things like redirect I/O and extend the compiler.  These words are maintained by the JForth system. (See FREEZE).   
  3342. Here is a partial list of JForth words which are deferred:  
  3343. EMIT        KEY         ?TERMINAL   CR          QUIT 
  3344. INTERPRET   FIND        :CREATE     NUMBER      ID.  
  3345. SOURCE      BLOCK       'WORD       LONGCFA,    CFA, 
  3346. FLUSHEMIT   COLDEXEC    ABORT       EXPECT      TYPE
  3347. To create a stuttering EMIT (2 emits/char) , we could try:  
  3348. DEFER OLD-EMIT
  3349. DEFER creates a new deferred word called OLD-EMIT .   
  3350. : EEMMIITT  ( char --- )
  3351.     DUP OLD-EMIT OLD-EMIT
  3352. : STUTTER   ( --- )
  3353.     WHAT'S EMIT  ( get the current value of EMIT )  
  3354.     IS OLD-EMIT  ( save this value in OLD-EMIT )  
  3355.     ' EEMMIITT IS EMIT
  3356. : STOP-IT!  ( --- )  WHAT'S OLD-EMIT IS EMIT  ;  
  3357. STUTTER  .S
  3358. Things are going to be hard to read nnooww.  After a while you'll get tired of tthhiiss ,, so enter:  
  3359. STOP-IT!   ( this will appear as SSTTOOPP--IITT!! )
  3360. DEFER and GLOBAL-DEFER are functionally identical in JForth.   
  3361. We recommend that you use a consistent naming convention for the words that you set the deferred words to.  Brackets and parentheses are common, for example:  
  3362. <ROBOT.OUTPUT>   or  (FILE.OUTPUT)   
  3363. If you have a complicated program with a lot of deferred words, you might put in a word to display the state of all your important deferred words:   
  3364. : SHOW-ME 
  3365.     WHAT'S OUTPUT.FUNCTION >NAME ID.  CR 
  3366.     WHAT'S INPUT.FUNCTION  >NAME ID.  CR
  3367. ;
  3368. Potential Problems with Defer
  3369. Deferred words are very handy to use, however, you must be careful with them.  Suppose you change EMIT so that it calls your word.  Then suppose you forget your word that EMIT now calls.  As you compile new code you will overwrite the code that EMIT calls and it will crash miserably. You MUST reset any deferred words that call your code before you FORGET your code.  The easiest way to do this is to use the word IF.FORGOTTEN to specify a cleanup word to be called if you ever FORGET the code in question.  In the above example using EMIT , we could have said:
  3370. IF.FORGOTTEN  STOP-IT!
  3371. Another problem that can occur is if you initialize a deferred system more than once.  In the above example, suppose we called STUTTER twice.  The first time we would save the original EMIT vector in OLD-EMIT and put in a new one.  The second time we called it we would take our new function from EMIT and save it in OLD-EMIT overwriting what we had saved previously.  Thus we would lose the original vector for EMIT .  You can avoid this if you check to see whether you have already done the defer.  Here is a rewritten form of the above example that does this check.
  3372. DEFER OLD-EMIT
  3373. ' QUIT  IS OLD-EMIT  ( set to known value )
  3374. : EEMMIITT  ( char --- , our fun EMIT )
  3375.     DUP OLD-EMIT OLD-EMIT
  3376. : STUTTER   ( --- )
  3377.     WHAT'S OLD-EMIT  ' QUIT =  ( still the same? )
  3378.     IF  ( this must be the first time )
  3379.         WHAT'S EMIT  ( get the current value of EMIT )  
  3380.         IS OLD-EMIT  ( save this value in OLD-EMIT )  
  3381.         ' EEMMIITT IS EMIT
  3382.     ELSE ."  Attempt to STUTTER twice!" CR
  3383.     THEN
  3384. : STOP-IT!  ( --- )
  3385.     WHAT'S OLD-EMIT ' QUIT =
  3386.     IF  ." STUTTER not installed!" CR
  3387.     ELSE  WHAT'S OLD-EMIT IS EMIT
  3388.         ' QUIT IS OLD-EMIT  ( reset to show termination )
  3389.     THEN
  3390. ;
  3391. IF.FORGOTTEN  STOP-IT!   ( make sure we clean up )
  3392. In the above example, we could call STUTTER or STOP-IT! as many times as we want and still be safe.  Look in the files JU:LOGTO, JU:DEBUGGER, and JU:HISTORY for examples of code that sets deferred system words in a safe manner.
  3393. Finally, it is important to insure that, whenever you install a word into a deferred function, the word being installed does not directly call that deferred function.  Doing so will create infinite recursion (actually, it will only recurse until it crashes).  For example, since the word . (dot) normally calls EMIT, you cannot:
  3394. ' . IS EMIT   ( never do this )
  3395. That would cause EMIT to call . which will call EMIT which will call . which will...get the idea?
  3396. Tools for FORGET
  3397. When you are testing a file full of code, you will probably recompile many times.  You will probably want to FORGET the old code before loading the new code.  You could put a line at the beginning of your file like this:
  3398. FORGET XXXX-MINE     : XXXX-MINE ;
  3399. This would automatically FORGET for you every time you load.  Unfortunately, you must define XXXX-MINE before you can ever load this file.  We have a word that will automatically define a word for you the first time, then FORGET and redefine it each time after that.  It is called ANEW and can be found at the beginning of most JForth files.  We use a prefix of "TASK-" followed by the filename just to be consistent.  This TASK-name word is handy when working with INCLUDE? as well.  Here is an example:
  3400. \ Start of file
  3401. INCLUDE? TASK-LOGTO JU:LOGTO
  3402. ANEW TASK-THIS-FILE
  3403. \ the rest of the file follows...
  3404. Notice that the INCLUDE? comes before the call to ANEW so that we don't FORGET LOGTO every time we recompile.
  3405. FORGET allows you to get rid of code that you have already compiled.  This is an unusual feature in a programming language.  It is very convenient in Forth but requires care.  Most problems with FORGET involve leaving addresses that point to the forgotten code that are not themselves forgotten.  This can occur if you set a deferred system word to your word then FORGET your word.  (See the section above on DEFERred words)
  3406. Another problem is if your code allocates memory, opens files, or opens windows.  If your code is forgotten you may have no way to free or close these things.   You could also have a problem if you add addresses from your code to a table that is below your code.  This might be a jump table or data table.
  3407. Since this is a common problem we have provided a tool for handling it.  If you have some code that you know could potentially cause a problem if forgotten, then write a cleanup word that will eliminate the problem.  This word could UNdefer words,  free memory, etc.  Then tell the system to call this word if the code is forgotten. Here is how:
  3408. : MY.CLEANUP  ( -- , do whatever )
  3409.     MY-MEM @ ?DUP
  3410.     IF  FREEBLOCK   0 MY-MEM !
  3411.     THEN
  3412. ;
  3413. IF.FORGOTTEN  MY.CLEANUP
  3414. Notice that the cleanup word checks before doing FREEBLOCK.  This word could be called any number of times and only the first time will have an action.  (Otherwise you would crash the second time.)
  3415. IF.FORGOTTEN creates a linked list node containing your CFA that is checked by FORGET.  Any nodes that end up above HERE after FORGET is done are executed.
  3416. Sometimes, you may need to extend the way that FORGET works.  FORGET is not deferred, however, because that could cause some real problems.  Instead, you can define a new version of [FORGET] which is searched for and executed by FORGET.  You MUST call [FORGET] from your program or FORGET will not actually FORGET.  Here is an example.
  3417. : [FORGET]  ( -- , my version )
  3418.     ." Change things around!" CR
  3419.     [FORGET]  ( must be called )
  3420.     ." Now put them back!" CR
  3421. ;
  3422. : FOO ." Hello!" ;
  3423. FORGET FOO
  3424. This is recommended over redefining FORGET because words like ANEW that call FORGET will now pick up your changes.
  3425. Local Variables      
  3426. The code for Local Variable support is in the file JU:LOCALS .  If you want to use locals in your program, place this line at the beginning of your file:
  3427. INCLUDE?  {  JU:LOCALS
  3428. In a complicated Forth word it is sometimes hard to keep track of where things are on the stack.  If you find you are doing a lot of stack operations like DUP SWAP ROT PICK etc.  then you may want to use local variables.  They can greatly simplify your code.  
  3429. You can declare local variables for a word using a syntax similar to the stack diagram.  These variables will only be accessible within that word.  Thus they are "local" as opposed to "global" like regular variables.  Local variables are self-fetching.  They automatically put their values on the stack when you give their name.  You don't need to @ the contents.  Local variables do not take up space in the dictionary.  They reside on the return stack where space is made for them as needed.  Words written with them can be reentrant and recursive.  You can declare how large local variables are to allow double precision, or larger.
  3430. Consider a word that calculates the difference of two squares, Here are two ways of writing the same word.   
  3431. : DIFF.SQUARES ( A B -- A*A-B*B ) 
  3432.     DUP * 
  3433.     SWAP DUP * 
  3434.     SWAP - 
  3435.   ( or ) 
  3436. : DIFF.SQUARES { A B -- A*A-B*B } 
  3437.     A A * 
  3438.     B B * - 
  3439. 3 2 DIFF.SQUARES  ( would return 5 ) 
  3440. In the second definition of DIFF.SQUARES the curly bracket '{' told the compiler to start declaring local variables.  Two locals were defined, A and B.  The names could be as long as regular Forth words if desired.  The "--" marked the end of the local variable list.  When the word is executed, the values will automatically be pulled from the stack and placed in the local variables.  When a local variable is executed it places its value on the stack instead of its address.  This is called self-fetching. Since there is no address, you may wonder how you can store into a local variable.  There is a special operator for local variables that does a store.   It looks like -> and is pronounced "to".
  3441. Local variables need not be passed on the stack.  You can declare a local variable that is uninitialized by placing it after a "vertical bar" ( | )character.  Uninitialized are exactly that. They are not automatically set to zero when created and may have any possible value before being set.  Here is a simple example that uses -> and | in a word:
  3442. : SHOW2*  
  3443.     { loc1 | unvar --  , 1 regular, 1 uninitialized }
  3444.     LOC1  2*  ->  UNVAR 
  3445.         (set uninitialized local to 2*LOC1 )
  3446.     UNVAR   .   ( print UNVAR )
  3447. ;
  3448. 3 SHOW2*   ( pass only 1 parameter, prints 6 )
  3449. Since local variable often used as counters or accumulators, we have a special operator for adding to a local variable It is +-> which is pronounced "plus to".  These next two lines are functionally equivalent but the second line is faster and smaller:
  3450. ACCUM   10 +   -> ACCUM
  3451. 10 +-> ACCUM
  3452. If you don't specify the size of the local variables, they default to 1 cell. You can specify the size in cells by preceeding the variable name with a number.   
  3453. : EXAMPLE { 2 a 2 b 4 c -- d1 } 
  3454.     a b  D+ 
  3455.     c ( note this fetches 2 double numbers ) 
  3456.     D+ D+ ; 
  3457. 5. 4. 6. 9. example  ( will return 24. )  
  3458. Local variables are normally self fetching, but that can be turned on and off using NO@ and YES@. When NO@ is specified, a reference to a local variable will result in its address being placed on the stack.
  3459. : EXAMPLE { a b c -- sum+1 } 
  3460.     a b +   +-> c  
  3461.     no@ ( turn self fetching off )   
  3462.     1 c +!
  3463.     yes@ ( turn it back on )
  3464.     c  ( fetch C ) ; 
  3465.  
  3466. 1 2 3 example ( will return 7 )
  3467. By combining NO@ and multiple cell variables, you can allocate local arrays 
  3468. : LOCARR { indx | 100 larr -- }
  3469.     NO@ LARR YES@ \ get address of base of array
  3470.     INDX CELLS \ calculate offset into array
  3471.     +  @  \ calculate address in array and fetch value there
  3472. ;
  3473. You can also specify that some local variables will automatically be returned:  
  3474. : EXAMPLE { a b c --> c } 
  3475.     a b + c + -> c
  3476. 1 2 3 example  ( will return 6 )   
  3477. The --> means that what follows up to the ASCII } is a list of variables to return.
  3478. If you name a local variable the same as a Forth word in the dictionary, eg. INDEX or COUNT, you will be given a warning message.  The local variable will still work, but the earlier defined word of the same name will not be accessible until the ; at the end of the definition is reached.  Other errors that can occur include, missing a closing '}', missing '--', or having too many local variables.
  3479. Logging to Files or the Printer  
  3480. The output of JForth can be made to echo to a file as well as the keyboard by changing the deferred word EMIT.  This is useful for generating records of your work,  dumping memory to a file for later analysis, etc.  If you are trying to generate formatted data files, you can get the code to work properly on the screen first.  Then just log your output to a file.  By sending the output to the file "PRT:", you can get JForth to send it's output to the printer.  The words needed to do this are defined in the utility file called "JU:LOGTO".   
  3481. $LOGTO  ( $filename -- , Send copy of output to file.)  
  3482. LOGTO  ( <filename> -- , Get filename and pass to $LOGTO)  
  3483. LOGSTOP  ( -- , Temporarily stop echoing. )   
  3484. LOGSTART  ( -- , Continue echoing, used after LOGSTOP )  
  3485. LOGEND  ( -- , Stop echoing, close file opened by LOGTO )
  3486. PRINTER.OFF  ( -- , turn off printer echo )
  3487. PRINTER.ON  ( -- , echo to printer as file PRT: )
  3488. As an example, if you want to dump some memory and have it printed, enter the following:  
  3489. : XXXDUMP  ( addr count -- )  
  3490.     " RAM:XXX" $LOGTO  ( Echo to file RAM:XXX ) 
  3491.     DUMP 
  3492.     LOGEND
  3493. ;
  3494. ' SWAP  100  XXXDUMP
  3495. TYPEFILE RAM:XXX
  3496. Word Usage Analysis     
  3497. Using this facility it is possible to keep track what of words are referenced, or not referenced, by your code.  This is useful when trimming unneeded words from your program.  It can also catch words that were defined and should have been used but weren't.   
  3498. CLEAR.MARKS   ( -- , Clears flag in all words to UNUSED state)  
  3499. START.MARKING.WORDS ( -- , Tells FIND to mark all words used.)  
  3500. STOP.MARKING.WORDS  ( -- , Turns off this facility )  
  3501. UNUSED.WORDS  ( -- , Print all UNUSED words in dictionary. )  
  3502. USED.WORDS    ( -- , Print all USED words in dictionary. )  
  3503. To use this facility, include the utility file "JDEV:UNUSED".  Then enter START.MARKING.WORDS .  From now on, all words referenced from the keyboard or from a file will be marked as used.  You can now load the program that you want to analyze.  To find out which words have been referenced by that program, enter USED.WORDS .  To find out which words were not referenced, enter UNUSED.WORDS .  To clear these flags, enter CLEAR.MARKS .  
  3504. Error Handling
  3505. File: JU:ERROR_CODES
  3506. What do you do when something goes wrong? If you can't allocate memory or open a file, what do you do next?  It is tempting to simply call ABORT when an error is encountered. This may work fine when debugging an application in Forth because you will be put back into the Forth interpreter. There you can investigate the source of the error and do something about it.  When you clone an application, however, abort will cause the program to quit.  If your user has just spent 2 hours drawing a masterpiece and the program quits when it can't allocate memory for a brush, you will have failed.  An application should always do its best to continue executing and to give the user a chance to save her work. 
  3507. Although it involves extra work, we recommend that routines subject to errors should return an error flag that is FALSE if everything went OK, and non-zero if an error occured. You can return different codes to indicate different types of errors if more than one is possible. A calling program can check the error code and act appropriately. 
  3508. We have provided a few tools to simplify, and perhaps standardize, error handling in JForth applications.  The first of these is a word that defines succesive error codes. 
  3509. ERR: ( n <name> -- n+1 , define constant ) 
  3510. This was used to define codes for the two most common errors in the following way: 
  3511. 1
  3512. ERR: ERR_FILE_NOT_FOUND        \ equals 1
  3513. ERR: ERR_INSUFFICIENT_MEMORY   \ equals 2
  3514. DROP  \ don't leave N on stack
  3515. When you encounter an error, you should inform the user by outputting a text message. You may want to put all of your error message text in a file that is read by your program as needed.  This simplifies translation to other languages. 
  3516. The dreaded GOTO
  3517. File: JU:GOTO_ERROR
  3518. Many languages have a command called GOTO that lets them jump directly from one place to another.  This seems like a handy thing but its use leads to a horrible disease called "spaghetti code".  Try to debug some old FORTRAN or BASIC program riddled with GOTOs and you'll know what I mean. It turns out that GOTO is really not needed in a high level language.  You can use IF ELSE THEN BEGIN UNTIL etc. to achieve the same effect and produce code that is much more readable and easier to maintain. 
  3519. You may now all gasp with horror and righteous indignation as I announce the addition of a GOTO to JForth. As I swing by my thumbs over the flames, let me explain why this is really OK. 
  3520. The one single use of GOTO that has been grudgingly confirmed as a good thing, is when used in error processing. Imagine that you are writing a routine that allocates memory several times.  Any one of these allocations could fail. You could use lots of IF statements but soon you will be indenting code right off the side of the screen. An alternative is to use a GOTO.ERROR after each allocation. If the allocation fails, the program will jump to the code following an ERROR: statement.  That code can clean up everything and return a proper error code to the caller. Here is a trivial example that demonstrates the use of GOTO.ERROR and ?GOTO.ERROR.  It uses local variables because they make it easier to keep the stack clean. 
  3521. include? task-error_codes ju:error_codes
  3522. include? task-goto_error ju:goto_error
  3523. include? { ju:locals
  3524.  
  3525. : TEST.GOTO { aa bb -- error? , simple example }
  3526.     aa 0= ?GOTO.ERROR
  3527. \
  3528.     bb 0<
  3529.     IF
  3530.         GOTO.ERROR
  3531.     THEN
  3532. \
  3533.     FALSE EXIT  \ exit causes immediate return to caller
  3534. \
  3535. ERROR:   \ continue from here if error
  3536.     >newline ." Uh Oh!" cr
  3537.     TRUE
  3538. ;
  3539. Try entering: 
  3540. 1  2 TEST.GOTO .
  3541. 0  2 TEST.GOTO .
  3542. 1 -2 TEST.GOTO .
  3543.  
  3544. Here is a more complex example that returns different error codes. Instead of calling EXIT we let the code that executes without error continue into the cleanup code. 
  3545. variable BIG-BUFFER \ hold pointers to allocated memory
  3546. variable MY-FILE
  3547.  
  3548. : DUMP.FILE  ( $filename -- error? )
  3549. \
  3550. \ try to open file
  3551.     $fopen ?dup
  3552.     IF
  3553.         my-file !
  3554.     ELSE
  3555.         ERR_FILE_NOT_FOUND GOTO.ERROR
  3556.     THEN
  3557. \
  3558. \ allocate memory to read data into
  3559.     memf_clear 200 allocblock ?dup
  3560.     IF
  3561.         big-buffer !
  3562.     ELSE
  3563.         ERR_INSUFFICIENT_MEMORY GOTO.ERROR
  3564.     THEN
  3565. \
  3566. \ read file into memory and dump
  3567.     MY-FILE @ BIG-BUFFER @ 200 FREAD
  3568.     BIG-BUFFER @ SWAP DUMP  \ dump what we got
  3569. \
  3570.     FALSE  \ return OK
  3571. \
  3572. ERROR:
  3573. \ free memory pointed to by variable if allocated
  3574.     BIG-BUFFER FREEVAR
  3575. \
  3576. \ close file pointed to by variable if open
  3577.     MY-FILE FCLOSEVAR
  3578. ;
  3579.  
  3580. Caution: when using GOTO.ERROR, make sure that you return the proper items on the stack.  Using local variables can greatly simplify this task.
  3581. 11 -      Miscellaneous Forth Tools
  3582.  
  3583.     Miscellaneous Forth Tools    11 -  
  3584.  
  3585.  
  3586.  
  3587.  
  3588.  
  3589.  
  3590. Chapter 12
  3591. System Internals     
  3592. The following memory map shows the layout of the JForth image in memory.
  3593.  
  3594.  
  3595. JForth is stored on a disk device in Amiga Binary Format, and when loaded into ram and executed, occupies one contiguous block of memory (with a few specific exeptions, as explained later).   
  3596. As the image may exist in either position-independent or relocatable form, it may reside at any location in either Chip or Fast ram (uses FAST, if available).   For this reason, all addresses mentioned here (and indeed, within  JForth  itself) are relative to the base of the JForth image, with location 0 being the first (bottommost) byte of the executable program.   
  3597. USER Variable Data Area    
  3598. This area holds the actual memory used for storage of USER variables, while the names and executable code used to generate the address of this location reside in the normal dictionary space.   
  3599. In  future versions of JForth, which may support a 'Forth multitasking' environment, each Forth task spawned  will receive a local copy of this area.   In single-task versions (3.0 and earlier),  there is functionally no difference from global VARIABLEs, in fact, the CLONE program will convert USER variables into global VARIABLEs in the standalone image.   
  3600. The size of the USER area determines the maximum number of USER variables which may be defined; each USER variable taking up 4 bytes.  Note that this area may  be increased by altering the value stored in #U and subsequently saving the image (via SAVE-FORTH ).  The saved image, when booted, will have the larger USER area.  Once increased, the USER area cannot be made smaller for a given image.   
  3601. The MAP command will display the  number of USER variables defined, as well as the number yet available in the current image   
  3602. Data Stack Area     
  3603. Immediately  below  the USER area is a 32 byte 'buffer-zone', protecting the USER area from programs which underflow the stack by as much as 8 items. No protection is provided for more errant programs.   
  3604. The Data Stack is assigned just below this zone, starting at the highest location and growing downward as numbers are 'pushed' on to it.   
  3605. Note that this area is not related to the Return (or 'program') Stack which will  be discussed later.  This area is solely for the manipulation of data items by Forth operatives such as +, -, etc.   
  3606. As data is placed on the Data Stack, the Data Stack Pointer (register A6) is decremented, resulting in a data area which grows downward toward the Dictionary Area. Consequently,  items removed or consumed from the Data Stack cause the Data Stack  Pointer to approach its original,  higher value.  Since debugged programs, over the  course of running, give back any Data Stack consumed, the normal  transient usage of this area does not interfere with dictionary expansion.  This is insured by maintaining sufficient Dictionary Area available.   
  3607. Extensible Dictionary Area     
  3608. As the JForth vocabulary is extended, new definitions are added serially, consuming the memory  immediately  above  the preceeding one.  The act of compilation, then, causes the Dictionary Area to grow upward toward the Data Stack,  resulting in an overall lowering of the available Dictionary Space.   
  3609. As mentioned, the amount of memory needed for the transient Data Stack is relatively small (less than 100  bytes,  typically), so Data Stack utilization is not usually a consideration.   However, the process of compiling causes  the Dictionary to grow toward the Data Stack by an amount directly  proportional to the size of the compiled  program; without sufficient Dictionary Area available, the Dictionary and Data Stack would meet with undesirable effects.   
  3610. JForth prevents this by monitoring the distance between the Data Stack and the Dictionary very closely during compiles.  The function ?STACK is used for this  purpose, aborting the compile if this area becomes less than 256 bytes.  Note that you may call ?STACK anytime within your own programs.   
  3611. Note that the Extensible Dictionary Area may be increased by altering the value stored in #K and subsequently saving the image (via SAVE-FORTH ). The saved image, when booted, will have the desired larger Dictionary area.   
  3612. Each definition added to the Dictionary consumes Dictionary Space; how much is determined by the function type and size.  However, regardless of the type and size, each function generates a Dictionary Header made up of a Link Field, Name Field, Size Field and Code Field.  The following diagram show the layout of a dictionary header in memory, in order of increasing address:
  3613.  
  3614. 1.   The LINK-FIELD ... 32 bits holding the address (JForth relative) of the preceeding  definition's NAME-FIELD.   The LINK-FIELD address may be derived from the CODE-FIELD address (see below) with >LINK .   
  3615. 2.   The  NAME-FIELD  ...  contains the text of the defined name; the first byte of this field is used as an 'attribute' byte as follows:  
  3616.  
  3617. The text of the name follows this byte; the text may be followed by a 'filler' byte to insure that the next field is word-aligned.  It is the address of the 'attribute' byte that is returned by >NAME , calculated from the CODE-FIELD address (see below).   
  3618. 3.   The  SIZE-FIELD ... The JForth compiler examines this field to find out how  the  word  is to be compiled (stored in bits 30 & 31) and what the size of the CODE-FIELD is, minus the RTS (stored in the lower word, bits 0-15).   
  3619. D31  D30 === Controls Compilation As Follows: 
  3620. ---  --- 
  3621.  
  3622.  0    0 .... will be CALLED if size > MAX-INLINE , 
  3623.                    otherwise INLINE, referred to as "BOTH".  
  3624.  0    1 .... must be CALLED.  
  3625.  
  3626.  1    0 .... must be compiled INLINE.  
  3627.  
  3628. (NOTE: bits 16-29 are reserved for future use).  
  3629. 4.   The  CODE-FIELD  ...  this field contains the executable 68000 assembly language and completely determines the runtime behavior of the word.  It is this address that is returned by ' (tick).   The CFA of a word is its code field address.
  3630. 5.  The PARAMETER-FIELD ... (optional)  In JForth, this refers to the data portion of a CREATE DOES> word ONLY.  The word >BODY will convert a CFA to a PFA of such a word. The PFA of a word is its parameter field address.
  3631.  
  3632. Kernel Dictionary Area     
  3633. This area is functionally identical to the Extensible Dictionary area in that it is comprised of function definitions which follow the Dictionary Header format described above.   
  3634. One difference, however is that the source code for this area is not provided in the JForth package, and therefore cannot be recompiled by the programmer (the Kernal is generated by a conventional 68000 Assembler).   
  3635. The Kernel Dictionary Area is, however, supplied as an assembled package and may be used to regenerate the  JForth system for various special cases...   
  3636. 1.  The programmer has altered the JForth system files (jf:).   
  3637. 2.  Regenerate with a different MAX-INLINE (JForth is normally generated with a MAX-INLINE value of 8).   
  3638. 3.  Generate  an absolute-minimum system for TURNKEYING (by booting COM:JKERNAL and stating  TURNKEYING ON before regenerating).   
  3639. 4.  Any other reason the programmer may think of.   
  3640. For more information on regenerating or customizing the JForth system, refer to the section "How to Generate a New JForth System", later in this chapter.   
  3641. The lastcompiled word in this area has, for historical reasons, been named TASK .   
  3642. Other memory Allocation / Utilization...   
  3643. In the process of using JForth, certain functions will allocate memory for systems use, and do so quite transparently to the user.   
  3644. Relocations Table      
  3645. As compiled images approach 140k in overall size, they will begin to assemble JSR operations in the 68000 long absolute mode of addressing.   
  3646. To the JForth  system, this means that a table of information must be kept about these references, so that the  Amiga Binary Loader can correctly 'relocate' them when the image is loaded into a different part of memory.   
  3647. JForth  automatically  generates  and  manages this table, completely transparent to the programmer.  Note,  however, that this table is not maintained within the dictionary; but is allocated from the general memory pool provided by the Amiga.   
  3648. When present, the ABSOLUTE ADDRESS of the table will be contained in a USER variable called ABSRELOCS .   
  3649. Each increase of 256 Long Relocations results in an additional 1k of memory allocated  from the Amiga OS; 'FORGET'ing programs that contain Relocations will automatically return memory when appropriate.   
  3650. Files and Memory Housekeeping...    
  3651. Provided the programmer uses the JForth-provided utilities to allocate memory and open files, JForth will keep track of the requests for these resources, returning them in BYE should the programmer forget.   
  3652. The data areas used to 'remember' memory and file usage is also allocated outside of the contiguous memory area  occupied by the executing JForth image.   
  3653. JForth Compiler      
  3654. CFA, is the JForth compiler.  It is a defered word set to (CFA,) .  The JForth compiler is very flexible.  You can define a word to be INLINE , CALLED or BOTH (depending on the system settings when the defined word is compiled).  The Forth function + is a BOTH type of word.  It is so small, 2 bytes , that it will always be compiled inline, since a call would be at least 4 bytes.    
  3655. DEF +  ( will display )  
  3656.     ADD.L   (DSP)+,TOS  
  3657.     RTS 
  3658. Compiling + in another word such as...   
  3659. : USE-OF-PLUS  + + + ; 
  3660. Results in the compiler creating...   
  3661. DEF USE-OF-PLUS  
  3662.     ADD.L   (DSP)+,TOS  
  3663.     ADD.L   (DSP)+,TOS  
  3664.     ADD.L   (DSP)+,TOS  
  3665.     RTS  
  3666. The default setting to new definitions is CALLED . This is for maximum compatiblity with threaded Forths.  So the above USE-OF-PLUS will  always be called. Note that USE-OF-PLUS is compiled without any threading of any kind.  The code for + is simply laid end-to-end, inline in the dictionary. This eliminates the 36 or more cycles that would be required for a JSR ... RTS between each of the only 10 cycles required for the actual addition. This is one of the main reasons JForth is at least 3 times faster than any threaded Forths.  Now look at this word:  
  3667. : EITHER    + + + + BOTH ; 
  3668. The BOTH before the ; tells the compiler to mark this word so that when used by another word, it may be compiled inline or called depending on the value of the MAX-INLINE user variable at compile time.  EITHER is 8 bytes long, the RTS is not included in the size.  If MAX-INLINE is set to anything less than 8 , a call will be compiled to EITHER . If MAX-INLINE is greater than 8 , the code for EITHER will be laid inline in whatever definition it's used in.  So,  
  3669. 1 MAX-INLINE !  
  3670. : EXAMPLE   EITHER  [ 9 MAX-INLINE ! ] EITHER ; 
  3671. DEF EXAMPLE 
  3672.     JSR     EITHER  
  3673.     ADD.L   (DSP)+,TOS  
  3674.     ADD.L   (DSP)+,TOS  
  3675.     ADD.L   (DSP)+,TOS  
  3676.     ADD.L   (DSP)+,TOS  
  3677.     RTS    
  3678. Note the first EITHER was compiled as a call.  After the MAX-INLINE is changed to 9 , EITHER was placed inline.   This dynamic sizing feature of JForth allows you to put speed where you need it, and save space where you don't need as much speed.   
  3679. Some words must be compiled INLINE , like R> >R (LOOP) and others.   
  3680. How to Generate a New JForth System 
  3681. These steps guide the programmer in creating a custom JForth development system.  This becomes necessary if the programmer has modified any of the 'jf:' (Extras:JForth) or any 'ju:' (JForth:util) files that are part of the normal JForth image.
  3682. NOTE: Modifying the JForth System such that this procedure is necessary can seriously affect our ability to render Technical Support, should you request it.  You may be asked to furnish a copy of your changes in this event, which can result in delays, if only for shipping purposes.  For this reason, we do not recommend modifications in this area unless suggested by Delta Research or otherwise if absolutely necessary.   
  3683. 1) From CLI, type:  run com:jkernal  
  3684. NOTE: number of bytes available will appear in HEX and the I/O will be in SLOW mode.  This will change as compilation progresses.   
  3685. 2) When the JForth window appears you can optionally select a tradeoff between speed and memory utilization.  If you have memory to burn and want a slightly faster Forth enter:  
  3686. 64 MAX-INLINE ! 
  3687. For a smaller but somewhat slower version, enter:  
  3688. 6 MAX-INLINE ! 
  3689. The default is 8 because JForth is plenty fast already and some systems may be short on memory.  You can set MAX-INLINE to anything you want but the practical range is 6 to 256.   If you set MAX-INLINE too high you may run out of memory.  You may want to selectively set MAX-INLINE high just for particular words that you want to optimize.
  3690. You are now ready to compile the first stage. Enter:  
  3691. INCLUDE JF:BUILDSYS 
  3692. When the compilation has completed, you need to save this first stage somewhere temporarily.  If you have plenty of RAM, you could save it in RAM:MINIMUM.  You could also save it on a blank floppy disk or on your hard disk.  Assuming you have an area reserved for temporary files called TMP:, enter: 
  3693. SAVE-FORTH TMP:MINIMUM    \ or wherever you want
  3694. 3) Enter:  BYE  
  3695. 4) From CLI, enter:
  3696. RUN   TMP:MINIMUM     \ or whatever you called it
  3697. 5) When the window appears, Enter:
  3698. INCLUDE   JF:LOADJFORTH  
  3699. The loader will ask if you want to INCLUDE the MODULE facility, the HASHed vocabulary search and History.  We recommend answering yes, 'Y', to all these questions.   If you do not use Module support then the code will probably not fit in this image.  In this case, increase #K then SAVE-FORTH to get a larger image.Modules that are created will be written to the MOD: directory.
  3700. 6) When the compile has stopped, the programmer may load in any additional files he desires (we recommend adding your files to the list in JF:LOADJFORTH).   
  3701. 7) Type:
  3702. SAVE-FORTH COM:JForth  
  3703. The just-created COM:JForth image will parallel the released version, reflecting, of course, any changes you have made.   You should now re-compile any applications you have written on top of this new JForth image.
  3704.  
  3705.  
  3706. 12 -      System Internals
  3707.  
  3708.     System Internals    12 -  
  3709.  
  3710.  
  3711.  
  3712.  
  3713.  
  3714.  
  3715. Chapter 13
  3716. Debugging       
  3717. by Phil Burk  
  3718. Debugging is the process of finding out why a program doesn't behave as it should.  The bad behavior can be anything from printing the wrong answer to crashing the machine.  Finding the source of bugs quickly is a skill that one develops through experience.  One can easily spend most of one's precious time debugging.  It is worth developing these debugging skills so that one has more time for developing and enjoying code.   
  3719. Debugging a program really starts before it is written.  For information on how to avoid bugs in the first place, please see the sections on programming style.   
  3720. In this chapter, we will discuss various debugging techniques as well as the various JForth tools specific to debugging.   
  3721. Tools Overview      
  3722. These tools can be used together to debug your programs.   
  3723. DEBUG is JForth's source level debugger.  It is described in detail later in this chapter.   
  3724. DEF will show you the assembly language code that is put together by the JForth compiler.  This is not for the faint of heart.  It is especially useful for debugging immediate words that compile code, or if you suspect that the compiler is generating code incorrectly.  This is extremely rare but can happen.  Please call us right away if it does.  Please see the section on the Disassembler for more details.   
  3725. DST will dump an Amiga structure showing you the name of the members and their value. It is in JU:DUMP_STRUCT.  Check it out.   
  3726. DUMP will display the contents of memory at a given address.  It is useful for examining data structures like the dictionary, and strings.  The stack diagram is:  
  3727. DUMP ( address count -- , dump memory ) 
  3728. ECHO ( -- addr ) is a variable.  If you set this to TRUE, the compiler will echo everything as it compiles.  This is handy if you are crashing during compilation.
  3729. FILE? is handy when you are examining unfamiliar code and need to know how a word is defined.  Enter FILE? followed by the name of the word to study.   
  3730. MAP can sometimes reveal problems related to dictionary size, number of relocations, etc.   
  3731. TRAPS sets the 68000 exception vectors so that errors like zero divide and odd addressing are trapped.  Activating TRAPS will prevent some of the common GURU messages.  TRAPS can be turned off with NOTRAPS .  TRAPS are automatically installed when you start JForth.   
  3732. UNRAVEL when executed, displays the return stack as a sequence of subroutine calls.  I will pause here to mention that RAVEL and UNRAVEL mean the same thing.  Look it up in a dictionary if you don't believe me. Include JU:UNRAVEL for this.  UNRAVEL is useful in a large program when you want to know who is calling a word.  Simply put a call to UNRAVEL inside the word that is being called.  A typical UNRAVEL display looks like:  
  3733. -150,664 
  3734. 16,576,646 
  3735. in voc: FORTH in word: (QUIT)  
  3736. in voc: FORTH in word: INTERPRET  
  3737. in voc: FORTH in word: DEFER-EXECUTE 
  3738. in voc: FORTH in word: (INTERPRET) 
  3739. in voc: FORTH in word: EXECUTE 
  3740. Debugging Hints      
  3741. Every debugging problem is unique and has a different solution.  There is no entirely rational way to find a bug quickly.   
  3742. Since most debugging is best done intuitively, I have designed this section as a random assortment of hints and questions that may lead you to an answer.  At some point in this process you will probably go "Ahah!" and be back in action.   
  3743. The first step in debugging is to come up with a fairly concise description of the bug.  An example might be, "My program is printing one too many numbers." Another might be, "Whenever I click the left mouse button, after drawing a rectangle, I crash.".  Once you have a concise description, you can proceed.   
  3744. ISOLATE THE ERROR.  Try to figure out exactly which word is not doing the right thing.  Execute each word in the offending area individually to make sure it matches its stack diagram.   
  3745. WALK THROUGH YOUR CODE.  Often a step by step analysis of the offending code is the best way to spot where things go wrong.   
  3746. CHALLENGE YOUR ASSUMPTIONS.  If the code is crashing, obviously something that you assumed was OK is not.  Reexamine that code that couldn't possibly be the problem.  I have known people to systematically reject all of the code as being the possible source of the error which leads them to the contradictory statement that the bug cannot exist but it does!  
  3747. DOES YOUR CODE CRASH AT COMPILE TIME? In other words do you get an error while you are INCLUDING a file.  If this is true then you might have a syntax error like a missing THEN or a missing ; .  You should also check your code for any IMMEDIATE words since they can execute at compile time and cause problems if they are buggy.  To find out where the problem is occurring, turn ECHO ON , then include the file.  The contents of the file will echo as it is being compiled.   
  3748. IS THE COMPILER NOT FINDING WORDS THAT YOU THINK IT SHOULD? Check for misspelled words, or a missing ( or ; .  You might also try REHASH or HASH.OFF in case there is a problem with HASHING.  You should also enter ORDER to see what vocabularies are being searched.  If you can't get it to recognize any words, try entering:  
  3749. ROOT ONLY FORTH 
  3750. to reset the vocabulary order.  Remember that if you are using ANEW, you may have to FORGET a file explicitly in order to INCLUDE something underneath it.  If you have just added an INCLUDE? this might be the problem.  You compile the new code then ANEW comes along and FORGETs it! You may also have overwritten part of the dictionary. WORDS will tell you this.   
  3751. START OVER AGAIN.  Sometimes you may be doing things right but are suffering from the lingering effects of a bug that you  fixed an hour ago. The old bug may have randomly poked into memory or set some variables wrong.  This can be wildly unpredictable.  Do a BYE then rerun JForth.  You may even want to reboot.   
  3752. DOES IT WORK THE FIRST TIME THEN NEVER AGAIN? This can be from a number of causes. When you first compile and run, your variables are zero.  What are they the second time you run? Did you do an ALLOCBLOCK or an FOPEN at compile time as you include? (Yuck!) If so what happened to that memory or that file?  The best way to handle these problems is to have an INIT word that does all required initialization, opens all files and windows needed, allocates all memory needed, initialize all data structures, etc.  Then have a TERM word that cleans up all this stuff.  Make sure you call the term word before recompiling the code.   
  3753. DID IT USED TO WORK BEFORE YOU MADE SOME CHANGES? Try to determine exactly what you changed.  It is good to test periodically before you go too far along the primrose path.  Keep frequent backups.   
  3754. USE   .S   LIBERALLY.  A few .S calls in your code can be very illuminating. This is not so important now that we have the source level debugger.   
  3755. ARE YOU OFF BY ONE?  Remember DO LOOPs go up to but don't reach their limit. Also remember this old problem.  You have a row of boxes labelled 15 through 25 consecutively.  How many boxes do you have? Ten? Wrong!! Eleven boxes.  Count them. This is known as the old "off by one" problem.   
  3756. COMMON AMIGA PROBLEMS.  Check to make sure that you are passing the Amiga absolute addresses in your function calls and structures.  See >ABS and >REL in the glossary.  Please remember as well that Forth and the Amiga operating system use a different format for representing strings.  Amiga strings are usually passed as NUL terminated 'C' strings.  These are a bunch of characters with a 0 at the end.  Forth typically have a byte containing a character count at the beginning followed by the characters.   
  3757. I TYPED SOMETHING BAD AND NOW MY FONT IS MESSED UP! Try entering ^O. That's control-O.  This will switch you back to the original font.   
  3758. Enough random chatter, now let's see how to really debug code.   
  3759. Source Level Debugger Tutorial    
  3760. The JForth Source Level Debugger, DEBUG , allows you to single step through your code.  This shows you exactly what each word is doing.  You can see the result of every DUP , SWAP , ROT , whatever, as it happens.   
  3761. Compiling with DEBUG{     
  3762. Let's try out the debugger and see how it works.  First we need to load the debugger.  It is a good idea to do this before you load the program you are working on.  To load the debugger, enter:  
  3763. INCLUDE? DEBUG{ JU:DEBUGGER 
  3764. To debug a word with DEBUG, we need to compile it with the debugger on. You use DEBUG{ and }DEBUG to turn on and off the debugger.  When the debugger is on, any word you compile has special information compiled into it for the debugger to use.  This makes the code much larger and slower so we only want to do this when debugging.  After you finish debugging, make sure you recompile without the debugger on.   
  3765. Let's define a simple word from the keyboard and then step through it. Enter:  
  3766. DEBUG{  ( turn on debugger ) 
  3767. : SUMN  ( N -- , print N*[N+1]/2 ) 
  3768.         DUP 1+ 
  3769.         * 2/ 
  3770. }DEBUG ( turn off debugger ) 
  3771. 3 SUMN .  
  3772. After the last line, you should see the answer 6 printed.   
  3773. Examining Code      
  3774. We can now single step through this program to see how it arrived at its answer. To debug, we put the word DEBUG right before the word we want to debug.  This should be after any stack parameters.  Enter:  
  3775. 0SP  ( clear stack if not already clear ) 
  3776. 3 DEBUG SUMN 
  3777. You will see a window called "JForth Debugger" pop up.  In the window, you should see a display that tells you you are entering SUMN.   
  3778. Entering:  SUMN >>>>>>>>>>>>>>>>>>>>>
  3779. ---------------------------------------------------------
  3780. [1] 3
  3781. 3DD46 : ------(   DUP                             |?_ 
  3782. You will also see a stack diagram with the 3 on the stack.  Below that will be a hexadecimal address and the word DUP.  This tells you that DUP is about to execute.  The cursor will be at the right of the screen waiting for a key.  Press the space bar.   
  3783. <SPACE> 
  3784. You should now see 3 3 on the stack which is what we would expect after DUP finishes.  We are now ready to do the 1+ .  Keep hitting the space bar until we finish the word.  At the end we saw an RTS instruction.  This meant that we were about to do a 68000 RTS, Return From Subroutine, instruction.  This corresponds to the semicolon at the end of a word.   
  3785. Now let's add some complexity by calling this word from another.  Enter:  
  3786. DEBUG{ 
  3787. : DOSUMS ( -- ) 
  3788.         100 5 DO 
  3789.                 I DUP . SUMN . CR 
  3790.         LOOP 
  3791. }DEBUG 
  3792. DEBUG DOSUMS 
  3793. Keep hitting the space bar until you see SUMN ready to execute.  Hit the space bar again.  You should now see a 15 on the stack.  This is the result of SUMN for N=5. You are now ready to execute the . instruction.  Hit <SPACE> and notice that the number 15 appeared in the original program window.   
  3794. Now let's go through the loop again but this time let's reexamine what SUMN is doing. Keep hitting the space bar until SUMN reappears in the command area.  If you miss it just go around again.  At this point we have two choices, we can hit space and skim over SUMN like before,or we can dive into SUMN and see it work.  With SUMN ready to execute, hit a D key or hit the return key.  The display should now say that you are in SUMN. The display of commands will indent to show that you are nested inside another word.   
  3795. To verify that we are indeed in SUMN, hit the W key.  This will display "Where" we are.  The display will indicate that DOSUMS has called SUMN.   
  3796. If you now continue to hit spaces, you will move through SUMN and eventually return to DOSUMS.  Thus <SPACE> will advance though a word while <RETURN> will dive into a nested word.
  3797. Stopping with a Breakpoint    
  3798. Now hit the space bar until we get back to the SUMN command.  Let's suppose we wanted to move more quickly through the loop.  It would be nice if we could just stop before each SUMN, see what N was then zoom forward to the next one.  To do this:  
  3799. Hit the B key.  
  3800. You should see a message that a "Breakpoint" was set.  This is like putting a stop sign by the call to SUMN.  You can have up to 16 breakpoints.  To advance quickly:  
  3801. Hit the G key.  
  3802. A 'G' tells DEBUG to "Go" until it hits the Breakpoint or finishes the word.  Notice that the answer was printed to the right of the DEBUG display.  Hit G a few more times.  You can watch the value of N on the stack increasing.  You will also see the answers appearing for each time around the loop.   
  3803. If we get tired of just doing one at a time, we can skip past the breakpoint several times.   
  3804. Hit the # key.  
  3805. Enter 7 , hit <RETURN> 
  3806. Notice that we saw seven answers appear before it stopped again.  If we want to just finish the word, we can "Clear" the breakpoint then "Go".   
  3807. Hit the C key.  
  3808. Hit the G key.  
  3809. You should now advance through the word at a rapid pace until you finish.
  3810. Note:  You can also specify a breakpoint by before you run the code using BREAKAT which is described in the Debugger glossary.
  3811. Stopping with Control-D     
  3812. When code is free running and you decide you want to start debugging, you can interrupt the code with a Control-D.  Enter  
  3813. DOSUMS  ( let it print a few ) 
  3814. Hit ^D  ( that's Control-D) 
  3815. (Control-D can be hit by HOLDING DOWN the <CTRL> key, then hitting a D, then releasing the <CTRL> key.)  
  3816. You should now be back in the debugger.  Hit W to find out which word you are in.   
  3817. You can now continue debugging as before.   
  3818. Debugging a Large Program    
  3819. If you want to debug a large program from a file, place the DEBUG{ }DEBUG commands around the include statement.  For example:  
  3820. DEBUG{ 
  3821. INCLUDE my-file  ( compile one of your programs ) 
  3822. }DEBUG 
  3823. DEBUG my-word  ( now debug it ) 
  3824. If you don't want to have the entire file in DEBUG mode you can place DEBUG{ }DEBUG around individual words in the file.  You can also use them within a word since they are defined as IMMEDIATE.   
  3825. Debugging a Cloned Program    
  3826. The Debugger will work with Cloned programs.  To debug a Cloned program, you must use DEBUG.START and DEBUG.STOP instead of the DEBUG command.  Here is an example of a debugging a cloned program.   
  3827. INCLUDE? CLONE CL:TOPFILE 
  3828. DEBUG{  ( compile with debug ) 
  3829. : TEST  ( -- , clone this puppy ) 
  3830.     DEBUG.START  ( open window and start debugging ) 
  3831.     ." Answer = " 2 2 + . CR  ( fancy program eh? ) 
  3832.     DEBUG.STOP   ( close window ) 
  3833. }DEBUG 
  3834. CLONE TEST 
  3835. SAVE-IMAGE TEST RAM:TEST 
  3836.  
  3837. ( now in the CLI window, enter: ) 
  3838. RAM:TEST 
  3839.  
  3840. You should see a window open and a normal debugging session will follow. Note: Since Clone removes the Forth headers, you cannot use the 'f' command in the debugger.  You may, therefore, want to assign custom functions to keys 7,8,9 using DEBUG.USER.7 , etc. Don't forget to recompile and reclone without the debugger when you are finished.  The debugger will add at least 15K to an application and makes it run much slower so don't release a program with the debug stuff in there.
  3841. IMMEDIATE Words
  3842. You will notice that IMMEDIATE words will also show the following word.  This is so that words like ' , ..@ , ." , IS , NEW: , etc. will print the word they are operating on.  For ." you will not see the entire string, just the first word.  Other IMMEDIATE words like IF ELSE and THEN will also show the following words even though this is not so important.
  3843. Source Level Debugger Glossary    
  3844. The words are supported by the Source Level Debugger - DEBUG.   
  3845. BREAKAT    (  <word>  [<command-in-word>] -- , set breakpoint )
  3846. This command can be used to set a breakpoint at a given command in a given word.  Consider the following example.
  3847. DEBUG{
  3848. : FOO ( N -- 1 )
  3849.     DUP 1+ SWAP - ;     }DEBUG
  3850. \  Break  ^ <- right there before SWAP in FOO
  3851. BREAKAT FOO SWAP
  3852. FOO
  3853. If you call BREAKAT without a command specified then it will set a breakpoint at the entry point of a word.  Use NOBREAKS to clear all breakpoints or hit 'C' in the debugger.
  3854. DEBUG{ ( -- , compile with debug on )  
  3855. }DEBUG    ( -- , compile normally )  
  3856. DEBUG    ( <word> -- , debug the word whose name follows)  
  3857. DEBUG.BREAK    ( -- , enter debugger when encountered )  
  3858. This word can be sprinkled through your program to force breakpoints.  
  3859. DEBUG.START    ( -- , open debugger window and start debugging )  
  3860. DEBUG.STOP    ( -- , close window and exit debugger )
  3861. DEBUG.USER.7    ( -- , deferred action for hitting '7' )
  3862. You can specify your own function to be executed when a '7' digit key is hit.  This allows you to use your own dump and diagnostic routines from the debugger, even when cloned.
  3863. : MYDUMP    ( -- , dump stuff of interest to user )
  3864.     ." my-var = " MY-VAR ?  cr
  3865. ;
  3866. ' MYDUMP  IS DEBUG.USER.7
  3867. DEBUG.USER.8     ( -- , deferred like DEBUG.USER.7 )
  3868. DEBUG.USER.9     ( -- , deferred like DEBUG.USER.7 )
  3869. NOBREAKS  ( -- , Clear all breakpoints except USER.BREAK?)
  3870. USER.BREAK?    ( address -- break? , user defined break )  
  3871. This is a deferred word that will be passed the address of the next Forth word to be executed.  The word can then decide whether to break into the debugger.  This is handy for making logical breakpoints.  You could, for instance break if a variable was out of range.  Here is an example user break.
  3872. }DEBUG  ( turn off to avoid recursion )
  3873. : MY.BREAK ( address -- break? ) 
  3874.         drop 
  3875.         VAR1 @ 100 > 
  3876. ' MY.BREAK IS USER.BREAK? 
  3877. Debugger One Key Commands    
  3878. When you are in the debugger,you can hit the ? key for a list of available interactive commands. I recommend playing with these commands to see what they do.   
  3879. Command Descriptions
  3880. Information
  3881. w - where?, who called who 
  3882. 6 - 680x0 register dump 
  3883.       Dump all 68000 Data and Address registers.  
  3884.       See assembler for more information.
  3885. m - memory dump from address on stack 
  3886.       This will treat the top of stack as an address 
  3887.       and dump the following 32 bytes.  
  3888. s - regular stack dump 
  3889.       This just calls .S 
  3890. r - return stack hex dump 
  3891. h - here 256 dump 
  3892.       Accurately display what's at HERE and on the PAD.  
  3893.       The PAD is at HERE 128 +.  
  3894. Action
  3895. f - forth, interpret one line 
  3896.       This will put you in Forth.  You can then 
  3897.       check variables. Check other words.  
  3898.       Do whatever.  Enter a blank line to finish.  
  3899.       The programs stack will be unaffected by your 
  3900.       actions. Remember, Forth itself is your most 
  3901.       powerful debugging tool.  (This feature is not
  3902.       available in Cloned programs.)
  3903.  
  3904. x - drop one number from stack 
  3905. n - push a number onto stack 
  3906. + - add a number to top of stack 
  3907.       These last three commands can be used to 
  3908.       alter the stack contents.  
  3909. Bases
  3910. 1 - decimal, set BASE to 10
  3911. 2 - binary, set BASE to 2
  3912. 3 - hex, set BASE to 16
  3913. User Keys
  3914. 7,8,9 - Execute DEBUG.USER.7,8,9
  3915. Control
  3916. b - set the breakpoint here 
  3917.       Set a breakpoint so that you will stop here 
  3918.       again if you ever come back.  
  3919. c - clear the breakpoint 
  3920. # - enter # breaks to skip 
  3921. u - up, continue until return 
  3922.       Finish the current word, go back into 
  3923.       DEBUG when you return to the calling word.  
  3924. j - jump over next instruction, don't execute it.
  3925. z - set user.break? to 0= , disabled 
  3926. l - look but don't touch 
  3927.       The program will continue while displaying 
  3928.       debugger information.  It will not stop 
  3929.       for Key Commands until you press a key.  
  3930. g - go, continue execution without debugging 
  3931. <SPACE> - single step on same level 
  3932. <CR> or d - dive down into word 
  3933. q - quit 
  3934.       Abort. Handy if continuing will cause a crash.  
  3935. I hope that this debugger will give you a window into your code.  It can also be a good learning tool for Forth beginners.   
  3936. 13 -      Debugging
  3937.  
  3938.     Debugging    13 -  
  3939.  
  3940.  
  3941.  
  3942.  
  3943.  
  3944.  
  3945. Chapter 14
  3946. 68000 Assembly
  3947. JForth  and 68000 Assembly Language
  3948. JForth offers an extensive set of tools for operating at the assembly language level.  These include:
  3949.     1. The JForth 68000 Reverse Polish Notation (RPN) Assembler
  3950.     2. The JForth 68000 Motorola-Style (Forward-Parsing) Assembler
  3951.     3. The JForth 68000 Disassembler.
  3952. This chapter includes documentation for each; some knowledge of 68000 assembly language topics is assumed; for additional technical information on the 68000, refer  to a Motorola 680xx Programmers Reference Manual.
  3953. JForth Register Utilization
  3954. To write successful assembly language programs, a basic understanding of how JForth uses the CPU registers is necessary.  This includes which registers are available for general use, and how to push numbers onto the data stack and pop them off.
  3955. 7 CPU registers are available for general use by the programmer.  These include D0, D1, D2, D3, D4, A0 and A1.  These may be altered at will, but are not preserved across calls to other JForth words, so relevant registers should be saved and restored if you do so.
  3956. JForth requires the remaining 9 registers for itself; these are either unavailable for use by the programmer, or useable only in prescribed ways (such as pushing numbers onto the stack and popping them off).
  3957. The following chart describes the JForth CPU register utilization:
  3958.     Register  JForth Name  Free to Use?   Used in JForth as:
  3959.        D0          --          Yes        --
  3960.        D1          --          Yes        --
  3961.        D2          --          Yes        --
  3962.        D3          --          Yes        --
  3963.        D4          --          Yes        --
  3964.        D5         ILOOP        No         F83 Loop Index #1
  3965.        D6         JLOOP        No         F83 Loop Index #2
  3966.        D7          TOS         No         Top of Stack
  3967.        A0         TEMP0        Yes        --
  3968.        A1         TEMP1        Yes        --
  3969.        A2          LOC         No         Pointer to LOCAL stack frame
  3970.        A3         +64K         No         Pointer to relative addr 64K
  3971.        A4          ORG         No         Pointer to relative addr 0
  3972.        A5          UP          No         Pointer to base of User Vars
  3973.        A6          DSP         No         Pointer to 2nd data stack item
  3974.        A7          RP          No         Return Stack/System Stack
  3975. Note that JForth provides alternate names for the reserved registers that are more descriptive of their specific functions.  These are recognized by both assemblers, and may be optionally included in the output of the disassembler.  See each respective section for additional information on register names.
  3976. JForth caches the topmost data stack item in the CPU register D7, also named TOS (Top-Of-Stack).  The second item on the stack (as well as any others) is stored on an actual stack in memory and is pointed to by register A6, or DSP (Data-Stack-Pointer).  Because of this arrangement, pushing a number on the data stack is a two-step process:
  3977. 1. Move the contents of the TOS register out to the data stack, adjusting DSP value to reflect a new element.
  3978. 2. Load the new number into TOS.
  3979. The process of popping a number off of the stack is even easier, requiring only one step:
  3980. 1. Move what DSP is pointing to into the TOS register, adjusting DSP value to reflect 1 less element.
  3981. Examples of how to do this are given in each assembler section; for now, remember that these operations involve the TOS register (D7) and the DSP register (A6).
  3982. One other reserved register can be useful to the programmer, but is ONLY READ FROM, and NEVER CHANGED!  This is register A4, also called the ORG register, and contains an absolute pointer to the beginning of the JForth image, the address that JForth considers 0, relative to itself.  The value of ORG is often added or subtracted from addresses to convert between the 'real' Amiga ones (ABSOLUTE) and the JForth ones (RELATIVE), as in the words >ABS and >REL.
  3983. JForth 68000 Forth Style Assembler   (RPN)
  3984. Compiling the RPN Assembler
  3985. Since the RPN Assembler is available as a MODULE, it is not usually required that the program be compiled.  Nonetheless, the Reverse Polish assembler can be compiled into the resident dictionary by entering:  
  3986. DETACHMODULE ASSEM
  3987. INCLUDE JF:ASM
  3988. RPN Assembler Usage
  3989. Here is an example of a simple RPN-assembled word.   
  3990. CODE DOUBLE  ( n -- n*2 , Double top of stack.) 
  3991.     TOS DN  TOS DN  ADD  ( Add TOS to itself.) 
  3992. END-CODE
  3993. 7 DOUBLE .
  3994. The word CODE activates the Reverse-Polish Assembler; subsequent input is interpreted in the ASSEMBLER context.  One ADD instruction follows; source operand first, destination operand second, finally the opcode.  The whole sequence ends with the END-CODE operator, which deactivates the ASSEMBLER after installing an RTS instruction as the final 68000 directive in this small program  (ALL JForth words MUST end in an RTS).  Please note that if an RTS is specifically included as the last instruction in the word being assembled, END-CODE will NOT append another one.   
  3995. RPN Assembler Register Names      
  3996. Since they conflict with hex numbers, the normal names for the registers (A0, D4, etc.) cannot be used by the RPN Assembler.  Instead, a convention has been adopted whereby the RPN-acceptable name is formed as a single word, beginning with the NUMBER of the register, followed by DR for data registers and AR for address registers.  For example, 0AR represents address register 0, 4DR is data register 4, and so on.
  3997. Additionally, all of the JForth functional names such as TOS and DSP are available.
  3998. Motorola Addressing Modes and RPN Assembler Equivalence
  3999. This table describes the various addressing modes available.   
  4000. Forth address mode         Motorola        description
  4001.                             example
  4002. DN       ( REG ---)          d0       == data register direct  
  4003. AN       ( REG ---)          a1       == address register direct  
  4004. A@       ( REG ---)          (a1)     == address register indirect
  4005. A@+      ( REG ---)          (a2)+    == A@ then inc reg by size
  4006. -A@      ( REG ---)          -(a3)    == dec by size, then A@
  4007. AN+W     ( AREG N---)        9(a1)    == address + word indirect
  4008. AN+R+B   ( AREG REG BYTE---) 5(a2,d3) == addr+reg+byte indirect  
  4009. ABS.W    ( N---)             1000     == absolute address word
  4010. ABS.L    ( N.LSW N.MSW---)   2000     == absolute address long
  4011. PC+W     ( W ---)            7(pc)    == pc + word 
  4012. PC+R+B   ( REG BYTE---)      9(pc.a2) == pc + reg + byte
  4013. #        ( N-OR-D---)        #4       == immediate data
  4014. Here are some examples of using the different addressing modes with a MOVE instruction, and the Motorola-style equivalent.   
  4015. Source            Destination   Opcode      Motorola equiv.
  4016. 0DR DN              0AR AN       MOVE    | MOVE.L D0,A0
  4017. 0AR A@              1AR A@+      MOVE    | MOVE.L (A0),(A1)+
  4018. 0AR -A@             1AR 50 AN+W  MOVE    | MOVE.L -(A0),50(A1)
  4019. 1AR 0DR 30 AN+R+B   100 ABS.L    MOVE    | MOVE.L 30(A1,D0.L),100
  4020. 2000 ABS.W          50 PC+N      MOVE    | MOVE.L 2000,50(PC)
  4021. 34 #           0DR 100 PC+R+B    MOVE    | MOVE.L #34,100(PC,D0.L)
  4022. RPN Assembler Support Words.    
  4023.  A data-length may be specified with one of these 3 operators:
  4024.  BYTE -- declares 8 bit data-size
  4025.  WORD -- declares 16-bit data-size
  4026.  LONG -- declares 32-bit data-size  ( default )
  4027.  The following examples illustrate the use of the size specifiers:
  4028.       Reverse Polish                     Motorola
  4029.  $ 7F #  0DR DN        BYTE AND       AND.B  #$7F,D0
  4030.  0DR DN  0AR AN        WORD MOVE      MOVE.W D0,A0
  4031.  0AR 0DR WORD 0 AN+R+B BYTE TST       TST.B  0(A0,D0.W)
  4032.  These two words generate local labels for branching...
  4033.  MARK ( --- )  ( BR# --IN-- )    ( create a label number ) 
  4034.  BR:  ( #br -- dest-addr #br  )  ( post fix create a label )
  4035. The only difference is the manner in which they accept the argument specifying the branch location, either PRE- or POST-FIX notation.  This example illustrates both:
  4036.  CODE TEST-SIGN  ( n1 -- result , -1=negative 0=zero 1=positive )
  4037.           TOS DN    TST      ( test register contents )
  4038.           2 BEQ    ( just leave if its zero by branching to '2' )
  4039.           5 BMI              ( if negative, branch to 5 )
  4040.           1 #  TOS DN MOVEQ  ( positive if here, set result = 1 )
  4041.           2 BRA              ( and exit )
  4042.  MARK 5   -1 # TOS DN MOVEQ  ( negative if here, set result = -1 )
  4043.  2 BR:    RTS
  4044.  END-CODE
  4045. Note that the numbers used to specify the branch locations need not be sequential, but each one may only specify one location (paired only once with BR: or MARK) within the CODE/END-CODE combination.  The same numbers may again be used in the next CODE word.
  4046. You may find words in the ASM source code that are not explained in this chapter.   These are JForth Assembler  INTERNAL words that should NOT be called from other programs.    
  4047. Non-Standard Opcodes      
  4048. Those 68000 opcodes that reference the status register (SR), user stack pointer (USP), or condition codes register (CCR) are available in the JForth RPN Assembler as custom opcodes which accept a single source or destination operand.  Examples...   
  4049. ORG  TOS  0 AN+R+B  MOVE-FROM-SR   ( move status reg to addr on stack )
  4050. $ 0f #              ANDI-CCR         (   zero   all  but  lower  4  bits  of  CCR )               
  4051. The  entire  list follows.  IMPORTANT!!! Those marked as "Privileged" should ONLY be used in interrupt code!!!
  4052. Opcode        Privileged
  4053. MOVE-TO-USP         X
  4054. MOVE-FROM-USP       X
  4055. MOVE-TO-SR          X
  4056. MOVE-FROM-SR        X
  4057. MOVE-TO-CCR
  4058. ANDI-SR             X
  4059. EORI-SR             X
  4060. ORI-SR              X
  4061. ANDI-CCR       
  4062. EORI-CCR       
  4063. ORI-CCR       
  4064. Standard Opcode Mnuemonics     
  4065. These function according to the Motorola standard, except as noted.
  4066. LINK MOVEM MOVEP TRAP CMPM MOVEQ
  4067. RTR TRAPV RTS RTE RESET NOP STOP SWAP UNLK EXT TAS ABCD SBCD 
  4068. CLR NEG NOT TST NEGX CMPI ORI ANDI SUBI ADDI EORI MOVE
  4069. AND OR SUB ADD EOR CMP MULS MULU CHK DIVS DIVU LEA SUBQ ADDQ
  4070. PEA JMP* JSR* NBCD EXG ROR ROL LSR LSL ROXR ROXL ASR ASL ADDX SUBX
  4071. Bxx** (branch on condition) DBxx** (decrement & branch on condition) 
  4072. BSR***
  4073. SCC SLS SCS SLT SEQ SMI SF SNE SGE SPL SGT ST SHI SVC SLE SVS
  4074.  
  4075.   * - Use  ] <name> [  instead of Jxx (invokes compiler to CALL word)
  4076.  ** - accepts a local label, for example:   BNE  1$
  4077. *** - Usage:   ' <wordname> BSR    (forces PC-relative call)
  4078. More RPN Examples      
  4079. ( Demonstrate accessing a Variable )
  4080. VARIABLE MY-VAR
  4081. CODE SHIFT-MY-VAR! ( N -- , Shift data in MY-VAR N times left. )
  4082. \
  4083. \ invoke compiler; generate variable address...
  4084.     ] MY-VAR [               ( -- N MY-VAR )
  4085. \
  4086. \ get a copy of N into d0...
  4087.     DSP A@  0DR DN  MOVE     ( -- N MY-VAR ) ( d0=shift count )
  4088. \
  4089. \ do the shift...
  4090.     0DR DN  ORG TOS 0 AN+R+B  ASL   ( -- N MY-VAR )
  4091. \
  4092. \ drop both numbers from the stack...
  4093.     CELL #  DSP AN  ADD       ( -- MY-VAR ) ( same as NIP )
  4094.     DSP A@+ TOS DN  MOVE      ( -- )        ( same as DROP )
  4095. END-CODE
  4096. This example demonstrates local branches, and also invoking the compiler (via ] and [)to create a call to another Forth word.  Note how D0 is saved while calling EMIT.   
  4097. CODE PLOT# ( N -- , emit N dashes )
  4098.       TOS DN   0DR DN   MOVE   ( keep count in D0 )
  4099.       DSP A@+  TOS DN   MOVE   ( drop count and reload TOS)
  4100. 1 BR: TOS DN   DSP -A@  MOVE   ( save TOS )
  4101.       ASCII - # TOS DN  MOVEQ  ( load '-' character into TOS )
  4102.       0DR DN   7AR -A@  MOVE   ( save D0 on return stack)
  4103.       ] EMIT [                 ( emit dash )
  4104.       7AR A@+   0DR DN  MOVE   ( restore D0 )
  4105.       1 # 0DR DN SUBQ          ( decrement loop counter )
  4106.       1 BNE                    ( loop until done )
  4107. END-CODE
  4108. Additional RPN Assembler Features     
  4109. RPN Assembler Usage in Colon Definitions
  4110. As long as you do not use the branching operators (Bcc, DBcc, BR: and MARK), you can activate the RPN assembler during normal compilation, as in the following example.   (If you use the assembler as a MODULE and not compiled resident in your dictionary, you need to insure the ASSEM module is loaded via GETMODULE ASSEM for this feature).   
  4111. : SUM*2 ( a b -- [a+b]*2 )
  4112.    +  [ ALSO ASSEMBLER  TOS DN TOS DN LONG ADD   PREVIOUS ] ;
  4113. RPN Assembler Macros
  4114. Similarly,  to do Macros in JForth RPN assembler, simply write a colon definition that has assembler words compiled into it.  (This cannot be done if you need to branch using BR: or MARK.  Also, the RPN assembler MUST be resident in the dictionary, and NOT loaded as a MODULE.  See the above section Compiling the RPN Assembler to achieve that configuration).   
  4115. : M.DOUBLE   [ ALSO ASSEMBLER ]  TOS DN  TOS DN  ADD
  4116.              [ PREVIOUS ] ;  IMMEDIATE
  4117. When this word is used within another definition (as follows), it will invoke the assembler to create the ADD instruction inline.   
  4118. : DOUBLE-MY-VAR ( -- , double the contents of a variable MY-VAR )
  4119.   MY-VAR @  ( -- my-var-data )   \ get value in MY-VAR
  4120.   M.DOUBLE  ( -- my-var-data*2 ) \ compile above ADD inst inline
  4121.   MY-VAR !  ( -- )  ;            \ put it back
  4122. The RPN assembler is unique in this ability to create macros; this is not currently possible with the Forward Assembler.  Unfortunately, the disadvantage of not being able to use the RPN assembler as a MODULE usually outweighs the benfit of this somewhat obscure feature.  
  4123. The RPN Assembler as a MODULE   
  4124. In JForth V1.3 and higher, the RPN Assembler may be compiled and saved as a MODULE (as is the default for the release version, in MOD:ASSEM.MOD).  The standard procedure for recompiling the com:JForth image, JF:LOADJFORTH, automatically regenerates the .MOD file if MODULE support is included.   
  4125. When implemented as such, the CODE and ;CODE keywords will automatically load the ASSEM module from MOD: if needed.
  4126. When the RPN Assembler is being used in module form, its directives may NOT be used to build assembler macros, described above.
  4127. Motorola-Style (Forward-Parsing) Assembler    
  4128. As many knowledgeable 68000 assembly-level programmers will admit, a non-standard reverse-polish syntax for a Forth assembler seems an additional burden to learn, simply to program in this 'lowest-of-levels'.  While the inherent 'macro-ability' and interactivity of the RPN assembler is an important gain, the Forward-Assembler environment features familiar Motorola formats as well as support for 'interactively' accessing elements of the JForth dictionary.   
  4129. You can see additional examples of Forward Assembler usage in the files JF:HASHING, JIFF:UNPACKING, CL:STARTJFORTH.ASM.
  4130. Please note that the Forward Assembler does not currently support the BLOCK environment; it may only be invoked within standard ascii text files accessed with INCLUDE, or from the keyboard.
  4131. Compiling the Forward Assembler     
  4132. Since the Foward Assembler is available as a MODULE, it is not usually required that the program be compiled.  Nonetheless, the Forward Assembler may be compiled into the resident dictionary by entering:  
  4133. DETACHMODULE ASSEM
  4134. INCLUDE JF:FORWARD-ASM
  4135. Forward Assembler Usage       
  4136. The Forward-Assembler is invoked with the "ASM" keyword, followed by the name of the word to be created (similar to the use of ":" when compiling a HIGH-LEVEL word).  Assembly-language mnemonics then follow, one statement per line.   
  4137. Finally, the last line begins (and ends) with the "END-CODE" operator, terminating the assembly-mode and resolving/verifying the just-created word.  An 'RTS' instruction is automatically assembled by this operation (ALL JForth words MUST end with RTS!) if necessary.   
  4138. This is illustrated by the following simple example, called ADD2, which adds the top two items on the stack...   
  4139. ASM ADD2   ( a b -- a+b )
  4140.     ADD.L  (A6)+,D7 
  4141. END-CODE 
  4142. The overall syntax adheres closely with Motorola standards; the following fields, based on character position, are defined:  
  4143. LABEL  OPCODE  OPERAND      COMMENT (rest of line is ignored)
  4144. 5$:    add.l   (a0)+,d0     add what A0 points to with D0 
  4145.        move.l  d0,d1        copy the sum into d1
  4146.        bne.s   5$           do it again if 'non-zero'
  4147. The following notes apply to each specific field...   
  4148. The Forward Assembler Label Field     
  4149. The first column of each line marks the beginning of the Label Field.   
  4150. The first character of this field must be one of 3 things: whitespace (blank or TAB), the beginning of a Forth comment, or begin a properly-formatted local label.   
  4151. The Forward-Assembler supports the use of Motorola-style local labels.  A declaration begins in column 1, and consists of the label VALUE followed by "$:"  (for example...  18$:).   
  4152. Currently, only one class of instruction may operate on declared labels; those which conditionally BRANCH on a tested condition.  BEQ (branch-if-equal) and DBEQ (decrement-&-branch-until-equal) are examples of this class.   
  4153. The following illustrates a test & branch condition.  Here, the tight loop will be repeated until register D0 equals zero...   
  4154. 1$:    subq.l  #1,d0    subtract 1 from d0... 
  4155.        bne     1$       if not equal to zero, branch to 1$
  4156.  
  4157. ... <<< EXECUTION CONTINUES HERE WHEN D0 = 0 >>>
  4158. Please note that label values MUST BE UNIQUE, but only between the same ASM and END-CODE combination.  Once another ASM has begun, the values may be reused.  Also, any DECIMAL value may be used; the programmer is not restricted to using sequential values.   
  4159. The Forward Assembler Opcode Field     
  4160. This field contains standard Motorola-style 68000 mnemonics in either case, and, where necessary, the size-specifying suffix .B, .W, .S, or .L.   
  4161. A few JForth-specific commands are also scanned for to provide greater flexibility:   
  4162. If the opcode field contains CALLCFA the next text is considered the name of a JForth word, and a call to that word will be compiled in the most efficient manner possible (do NOT use the JSR or JMP instruction to reference NAMED words...use CALLCFA).   The following example reads two variables, DIVIDEND and DIVISOR, calls / to divide them and leaves the result on the stack:
  4163.     ASM DIV2  ( -- n , divide the variables )
  4164.             callcfa   DIVIDEND         ( -- DVNDvar )
  4165.             move.l    0(org,tos.l),tos ( -- DVDN )
  4166.             callcfa   DIVISOR          ( -- DVDN DVSRvar )
  4167.             callcfa   @                ( -- DVDN DVSR , same as move.l..)
  4168.             callcfa   /                ( -- QUO )
  4169.     END-CODE
  4170. It is possible to explicitely force a PC-relative call to be assembled to another named word as long as it is within +-32K of the calling instruction.  This is useful to build interrupt code where the ORG register is not yet setup.
  4171.             move.l    #[ascii -],d0   put a '-' character in d0
  4172.             bsr       ProcessChar     call some char processor routine
  4173. If the opcode field contains FORTH{, all text up to the following } character (or end-of-line) will be sent to the JForth INTERPRETER and executed.   This example invokes the compiler to create a reference to an Amiga Library function:
  4174.             move.l    tos,-(dsp)   ( -- prevTOS )
  4175.             move.l    #$40,tos     ( -- $40 )
  4176.             FORTH{  ] callvoid dos_lib Delay [  }   ( -- )
  4177. The Forward Assembler Operand Field     
  4178. This field describes any operands needed by opcode.  All standard Motorola-style effective address formats are recognized, as well as a few JForth-specific patterns which are here described.
  4179. The Forward Assembler, as supplied in JForth versions 3.0 and earlier, does not directly support references to the SR (Status Register), CCR (Condition Codes Register) or the USP (User Stack Pointer), but access to the related RPN assembler operatives is always possible.  For example...
  4180. \ Zero all but lower 4 bits of CCR...
  4181. FORTH{ ASSEMBLER   $ 0f  #  ANDI-CCR ( andi #$f,ccr )    PREVIOUS }
  4182. A special construct affords access to most JForth entities; in places where a numeric argument is expected, the [ and ] characters can be used to delimit a string to be submitted to the JForth INTERPRETer (similar to the FORTH{ operative, described above).  This is useful to apply defined data CONSTANTs, but can be used for other purposes.  The following example checks if the value in TOS is equal to a pre-defined CONSTANT (in this case, an Amiga mask describing memory):
  4183. cmp.l  #[MEMF_CHIP],tos     is the value in tos = mask?
  4184. Another example illustrates how this feature can also be used to pre-calculate operand 'literal' values:
  4185. move.l #[8 1024 *],tos      put '8K' in TOS
  4186. A third example reads the 4th element of a 32-bit array, base address in a0, into register d0:
  4187. move.l [3 cells](a0),d0     read a0 plus 12, indirect
  4188. Any valid sequence of Forth commands may exist between the [ and ] characters, as long as it meets the following criteria:
  4189. 1. The expression has an overall stack diagram of  ( -- n1 ) .
  4190. 2. Due to the parsing requirements of the Motorola assembly format, the text between the [ and ] delimiters may NOT contain any of the following 6 characters:   (  )  ,  .  [  ]
  4191. NOTE: You should never use the [ and ] characters to generate an ADDRESS for an instruction.  An example of this would be:
  4192. move.l  #[' NOOP],tos
  4193. Such code will run in the JForth dictionary, but is not compatible with the CLONE program.  You can use FORTH{ and the compiler directive ALITERAL to create code which will push an address on the stack in a CLONEable way:
  4194.             FORTH{  ' NOOP  ] ALITERAL [   }
  4195. NOTE: between the ASM and END-CODE, numbers are INTERPRETed in DECIMAL; preceed hex numbers immediately with a $ character, for example $FFFE.  
  4196. Example of Accessing Structure Members
  4197. Here is an example illustrating how to access members of an Amiga structure.  Structure members return their offset when referenced so we can use them directly between [ and ].  Make sure you use the proper size MOVE.  Notice the MOVE.W for the width.  Notice also that we clear the high bits of D7 first because MOVE.W onlt sets the low bits.  This example also illustrates conversion between absolute and relative addresses.  This next word takes a relative window address and prints its title and width.
  4198. ASM  WINDOW.INFO  ( window -- )
  4199.     MOVE.L    D7,A0        \ relative window address to A0
  4200.     ADD.L        ORG,A0    \ convert to absolute address
  4201.     CLR.L        D7            \ clear high bits of TOS
  4202.     MOVE.W    [WD_WIDTH],D7    ; get width in TOS
  4203.     MOVE.L    D7,-(DSP)    \ save TOS
  4204.     MOVE.L    [WD_TITLE](A0),D7    ; get title in TOS
  4205.     SUB.L        ORG,D7    \ convert to relative for JForth
  4206.     CALLCFA    0COUNT    \ ( -- width address count )
  4207.     CALLCFA    TYPE
  4208.     CALLCFA    SPACE
  4209.     CALLCFA    .            \ print width
  4210. END-CODE
  4211. We can test this word by assembling it then entering:
  4212. INCLUDE JU:AMIGA_GRAPH
  4213. GR.INIT  GR.OPENTEST
  4214. GR-CURWINDOW @ WINDOW.INFO
  4215. GR.CLOSECURW  GR.TERM
  4216. Example of Referencing Variables from an Interrupt
  4217. If you need to reference a variable from an interrupt routine, you cannot use
  4218. CALLCFA    VAR1    \ NOT legal in interrupt routines
  4219. because that assumes that the 68000 registers are setup for JForth use.  In an interrupt, that will not be true.  In an interrupt you cannot use the JForth data stack, or call any word using CALLCFA, or call any word that uses the data stack.  Here is an example of referencing a VARIABLE and calling a subroutine using legal PC relative addressing:
  4220. variable VAR1
  4221. ASM INCVAR  \ increment VAR1
  4222.     LEA        [VAR1 HERE - 2-](PC),A0
  4223.     ADD.L        #1,(A0)
  4224. END-CODE
  4225. ASM    INTROUTINE
  4226.     BSR        INCVAR    \ PC relative call so OK
  4227.     CLR.L        D0            \ tell Amiga we're done
  4228. END-CODE
  4229. See the files JD:DEMO_INTERRUPT and JD:HIGH_INTERRUPT for more examples.
  4230. The Forward Assembler as a MODULE   
  4231. In JForth V1.3 and higher, the Forward Assembler may be compiled and saved as a MODULE (as is the default for the release version, in MOD:ASSEM.MOD).  JF:LOADJFORTH, the standard procedure for recompiling the com:JForth image, automatically regenerates the .MOD file anew if MODULE support is included.   
  4232. When implemented as such, the ASM keyword will automatically load the ASSEM module from MOD: if needed.
  4233. DISM - JForth Disassembler     
  4234. Compiling the Disassembler     
  4235. Since the Disassembler is available as a MODULE, it is not usually required that the program be compiled.  Nonetheless, the Disassembler can be compiled into the resident dictionary by entering:  
  4236. DETACHMODULE DISASSEM
  4237. INCLUDE JF:DISM
  4238. Disassembler Output      
  4239. DISM, and its related forms, sends output to the standard EMIT device.  It is of the form:  
  4240.   1D14  move.l  tos,-(dsp)       2D07         "-."
  4241.   1D16  moveq.l #$20,tos         7E20         "~ "
  4242.   1D18  bsr.w   26D0  = EMIT     6100 09B6    "a..."
  4243.   1D1C  rts                      4E75         "Nu"
  4244. The first column indicates the address of the code.  This may be displayed in several modes (see DISM, RISM, ADISM and RELDISM below), but normally represents the JForth relative address.   
  4245. The second column is the assembly language mnemonic.   
  4246. The third column displays the operands (for options, see DISM-NAMES, below).   
  4247. In the fourth row is shown the actual hex code of the opcode and related operands.
  4248. By default, the fifth column displays ascii-equivalent characters, helpful in identifying strings.  (for options, see DISM-CYCLES, below).
  4249. "Automatic" Disassembly Features     
  4250. All forms of the 'automatic' disassembly words will keep track of forward branches, and only stop disassembling when a 'return' type opcode is displayed that does not have a pending conditional branch past it.  (?PAUSE is called at the end of each line, though, so you can simply type QUIT to stop disassembling, or space bar to pause and RETURN to continue).   
  4251. All forms of 'automatic' disassembly will examine two state variables to determine runtime conditions for:  
  4252. 1. whether generic or JForth specific register names will be displayed.  (see DISM-NAMES, below) 
  4253. 2. whether the timing cycles will be displayed in the 5th column instead of the default ascii information. (see DISM-CYCLES, below)
  4254. These state variables are DISM-NAMES and DISM-CYCLES, respectively.  For example, to display the timing cycle information, enter  DISM-CYCLES ON then disassemble something, observing the 5th column.   
  4255. Timing cycles are of the form (xx:yy:zz) where:
  4256. xx = no. of 68000 bus cycles this instruction
  4257. yy = no. of 68000 bus cycles since beginning of word (ignores branches & loops)
  4258. zz = no. of microsecs since beginning of word (on std. A2000, 7.16 Mhz 68000)
  4259. NOTE: Timing cycles are estimates at best and largely for entertainment value.
  4260. CPU registers are displayed according to the state of DISM-NAMES as follows:  
  4261. DISM-NAMES = 0    DISM-NAMES != 0 
  4262.            a0        a0 
  4263.            a1        a1 
  4264.            a2        a2 
  4265.            a3       +64K  image-base+64K 
  4266.            a4        org  origin 
  4267.            a5        up   user pointer 
  4268.            a6        dsp  data stack pointer 
  4269.            a7        rp   return pointer 
  4270.            d0        d0 
  4271.            d1        d1 
  4272.            d2        d2 
  4273.            d3        d3 
  4274.            d4        loc  locals 
  4275.            d5       iloop 83-type loop index 1 
  4276.            d6       jloop 83-type loop index 2 
  4277.            d7        tos  top of stack 
  4278. NOTE: the same flag, DISM-NAMES also determines whether the disassembler will attempt to display the names of routines being 'called'.   
  4279. Disassembling within the JForth Image   
  4280. For examining code within the JForth image, the two most often used words are DISM and DEF.   
  4281. DISM  ( rel-addr -- )     \ for example,   ' D+ DISM
  4282. Disassembles from the relative address on the stack in 'automatic' mode (see above).  DISM does not recognize strings, and attempts to disassemble them.
  4283. DEF   (  <wordname> -- )  \ for example:  DEF D+
  4284. DEF attempts to find the next input word as a dictionary entry.  If it is successful, it disassembles from the code-field-address.  Note that DEF will recognize a compiled string, displaying its content in ascii form.   
  4285. Disassembling outside of the JForth Image  
  4286. Three words are useful for disassembling code that exists outside of the JForth image.   
  4287. ADISM ( abs-addr -- ) 
  4288. ADISM disassembles from the absolute address on the stack, with addresses labeled as such.   
  4289. RISM  ( rel-addr -- ) 
  4290. RISM disassembles from the rel-address as does DISM, but displays the first line as address 0, with successive addresses being labeled relative to the beginning of the disassembly.   
  4291. RELDISM ( org-addr rel-addr -- ) 
  4292. RELDISM changes the output addressing scheme similar to RISM, but accepts an additional parameter specifying the address to consider relative 0, the origin address.   
  4293. The Disassembler as a MODULE   
  4294. In JForth V1.3 and higher, the Disassembler may be compiled and saved as a MODULE (as is the default for the release version, in MOD:DISASSEM.MOD).  JF:LOADJFORTH, the standard procedure for recompiling the com:JForth image, automatically regenerates the .MOD file anew if MODULE support is included.   
  4295. When implemented as such, the following words will automatically load the DISASSEM module from MOD: if needed:  
  4296. DEF  DISM  RELDISM  RISM  ADISM  DISM-DONE?  DISM-WORD? 
  4297. INIT-DISM  DISM-CYCLES    DISM-NAMES DISM-ORIGIN .REGNAMES?
  4298. SHOW-CYCLES
  4299. When the Disassembler is being used in module form, these words also form the entire programmatic interface to the facility.   
  4300.  
  4301.  
  4302.  
  4303.  
  4304.     68000 Assembly    14 -  
  4305.  
  4306.     68000 Assembly    14 -  
  4307.  
  4308.  
  4309.  
  4310.  
  4311.  
  4312.  
  4313. Chapter 15
  4314. Forth 'BLOCK' Environment     
  4315. Before the advent of sophisticated operating system environments as that available on the Amiga, Forth systems have been uniquely self-sufficient in their approach to utilizing mass-storage.   
  4316. The resulting 'BLOCK' environment has been implemented as a pseudo- standard for disk-interfacing, and as such, does provide a small degree of transportability for high-level forth code.   
  4317. It is important to note, however, that SCREEN files, those created under BLOCK, are not compatible with AmigaDOS text files, being defferent in format (SCREENs do not have end-of-lines).
  4318. If you want to convert your BLOCK files to text you can do so using BLOCK2TEXT which is described at the end of this chapter.
  4319. AmigaDOS Incompatibilities      
  4320. Newcomers should note that files produced under the 'BLOCK' environment are not compatible with AmigaDOS text-based programs (editors, word-processors, spoolers, sorters, etc.).  For example, they cannot be listed (or printed) via the AmigaDOS TYPE command.  For those that wish to use the BLOCK environment, JForth provides both a line editor and a full screen editor, each described below.
  4321. Source files are typically aat least 3 times larger with BLOCK files, since all white space on a SCREEN is actual ASCII blank characters; there are no end-of-line characters.   
  4322. The management of source code is often cumbersome in SCREEN files as the programmer is forced to reference sections of the file via SCREEN NUMBERS, sequentially numbered 1024-byte 'blocks' of characters, with no standard means of referencing other files.
  4323. For these and other reasons, we strongly discourage the use of SCREEN files for Amiga development work;  it is provided for compatibility with existing source code and for those that prefer SCREENS.   
  4324. JForth will support the standard 'BLOCK' environment, after compiling certain source files; but has been specifically designed to fully utilize the AmigaDOS file-system and accompanying ASCII text files.  Certain JForth tools/utilities are not available under the 'BLOCK' environment:  
  4325. 1. TYPEFILE - since SCREEN FILES do not contain end-of-line characters, the output from thisASCII-file oriented program is not readable.
  4326. 2. READLINE - again rendered unusable, for the same reason.
  4327. 3. FILE? - not supported for words compiled from SCREENs, it requires end-of-lines.
  4328. 4. ASM - The Forward Assembler is also line-oriented.
  4329. 5. DEBUGGER - JForth can only compile in DEBUG mode within ascii files.
  4330. JForth supplied SCREEN utilities    
  4331. Support for the BLOCK environment is provided in 3 files:  
  4332. 1.  BLOCK  - this file provides the read/write, open/close, and display primitives, along with the necessary buffer management' words.
  4333. 2.  EDITOR - loads a 'line-editor' similar to that promoted by FIG (Forth Interest Group).  Defines the EDITOR vocabulary.
  4334. 3.  SCRED  - loads the JForth SCReen EDitor that fully interfaces with the above line-editor.  Extends the EDITOR vocabulary.  Line editor commands may be issued within SCRED.
  4335. Issuing the command  INCLUDE JDEV:SCRED  will cause these files to be compiled; they will require about 25K of dictionary area.   
  4336. Note that the command  INCLUDE JDEV:EDITOR  will load only BLOCK and EDITOR, saving about 10K, but providing only line-editing capabilities.   
  4337. Line Editor Operation and Glossary
  4338. To begin an editing session using the line editor, open the screen file via:  
  4339. OPEN-SCR <screen-filename>
  4340. To enter the EDITOR vocabulary, making available the words listed below, enter:
  4341. EDITOR 
  4342. To both display SCREEN #1 and select it for editing, type:
  4343. 1 LIST 
  4344. The EDITOR commands may now be used to modify the source.  As changes are made, the user may SAVE or SAVE-BUFFERS to write changes to disk, but these changes may not become permanently applied to the file until CLOSE-SCR is executed.
  4345. Any time while the SCREEN file is open, you may LOAD the file, specifying the SCREEN number to start LOADing from on the stack.
  4346. An example session might be...
  4347. OPEN-SCR ram:myScreens    \ will ask create? if doesn't exist
  4348. EDITOR                    \ expose the EDITOR vocabulary
  4349. 1 LIST                    \ list out screen 1
  4350. 1 CLEAR                   \ empty out the entire screen
  4351. 1 P : Hello  ( -- )       \ enter a small definition
  4352. 2 P   >newline ." Hello, world!" cr
  4353. 3 P ;
  4354. L                         \ LIST out the entire screen
  4355. 1 LOAD                    \ LOAD the screen (compile it)
  4356. HELLO                     \ execute the word
  4357. CLOSE-SCR                 \ all done with the file, tell AmigaDOS
  4358. The commands in the EDITOR vocabulary...
  4359. B  ( --  , Back-up the cursor by the number of characters at PAD.)
  4360. C  ( -- Copy the following text, inserting it at the cursor. )
  4361. C INSERT THIS WHERE THE CURSOR IS 
  4362. D  ( line# -- , Delete line#, but place its text at PAD. )
  4363. E  ( line# -- , Erase line# with blanks. )
  4364. F  ( <line> -- , search for line that follows )
  4365. Search forward from the cursor position, until the text is found, leaving the cursor just past the text.  If the text is not found, an error message is printed, and QUIT executed.
  4366. F THIS STRING 
  4367. H ( line# -- , Hold line# at PAD)
  4368.  Leave it untouched in the SCREEN.
  4369. I  ( line# -- , Insert the line at PAD before line# )
  4370. Move line# and all lines below it down.  Line 15 is lost.   
  4371. L  ( -- , Relist the current screen.)
  4372. M  ( n -- , Move the cursor N characters.)
  4373. Negative is to the left.  Display the final destination line.  
  4374. N  ( -- , Find next occurrence of string last found by F or N.)
  4375. P  ( line# -- , Put new text on a line.)
  4376. 3 P THIS GOES TO LINE 3. 
  4377. R  ( line# -- , Replace line# with the text in PAD.)
  4378. S ( line# -- , Spread the screen at line#)
  4379. Move it and all lines below it down.  Line# becomes blank.  Line 15 is lost.   
  4380. T  ( line# -- line# , Type line# on the standard EMIT device)
  4381. Save its text in PAD.  
  4382. X  ( -- , Delete the next occurrence of the following text.)
  4383. X THIS TEXT 
  4384. CLEAR   ( scr# -- , CLEAR screen and select for editing.)
  4385. COPY  ( scr1 scr2 -- , COPY screen SCR1 to SCR2.)
  4386. DELETE  ( #chars -- , DELETE #chars before the cursor.)
  4387. EMPTY-BUFFERS  ( -- , Empty current contents of all buffers. )
  4388. SAVE-BUFFERS   ( -- , Write any updated buffers to disk.)
  4389. Leave in buffer.
  4390. SAVE  ( -- , Alias for SAVE-BUFFERS.)
  4391. TOP   ( -- , Move the cursor to the top of the screen.)
  4392. TILL  ( <line> -- , Delete all text from cursor to located text)
  4393. TILL THIS TEXT
  4394. MORE-SCREENS ( #scrs -- , Add #SCRS to current SCREEN file size)
  4395. SCRED ... the JForth SCReen EDitor  
  4396. SCRED is a sophisticated editing tool, useful when dealing with SCREEN files.  It fully interfaces with the EDITOR line-editor, providing instantaneous access to and from the editing environment.   
  4397. SCRED incorporates a command line feature, from which any editor or forth command may be executed.  This is particularly useful in using line-editor commands while in SCRED.   
  4398. A SCRED editing session may be invoked with:   
  4399. SCRED <screen-filename> 
  4400. This command will perform the above described line-editor OPEN-SCR, enter the EDITOR vocabulary and display SCREEN 1 of the file.
  4401. Once SCRED is entered, the user is presented with a text menu of possible single-stroke key operations.  At the top is listed the current screen number and filename while on the left side are the screen line numbers, for use with the line-editor.   
  4402. To the right is displayed the status of INSERT and WRAP.  When SCRED is in INSERT mode, characters typed will 'push' existing characters over, otherwise existing characters are simply overwritten.  The INSERT mode may be toggled via a key-stroke listed in the menu.   
  4403. The WRAP parameter indicates the number of lines that will be affected by the INSERT mode (or when characters are BACKSPACEd).  It is set from the command line as follows:  3 WRAP !  or  0 WRAP ! .   
  4404. 1 WRAP ! 
  4405. The 'Forth Cmd' key will cause the cursor to move below the displayed screen to the 'command line' at the bottom of the window.  There it will display the message '<SCRED>:' informing the user that it is waiting for input.   
  4406. At this point, the user may type in any FORTH or EDITOR command; when the command finishes, the cursor will return to the screen, available for more editing.  If the command causes the displayed screen contents to change, its appearance will be updated before the cursor returns.   
  4407. If the command generates an error, causing the system to execute QUIT, the message 'any key QUITs' will appear in the command line until the user presses a key.  This gives him the chance to see any error message in the command line before the SCRED window closes.   
  4408. SCRED may be exited by typing   
  4409. QUIT 
  4410. or
  4411. END-ED 
  4412. from the command-line, or simply typing the control key for the EXIT function.
  4413. NOTE that SCRED does not close the SCR-FILE when it exits.  This not only allows the programmer to LOAD the screen(s) he just edited, but also quickly get back to the same SCRED environment by typing:
  4414. SE 
  4415. This command will reopen the SCRED window to the same screen and cursor position it was last on when SCRED was exited.   
  4416. Once the programmer has finished with the file and exited SCRED, he should finally close the file with       
  4417. CLOSE-SCR 
  4418. It is this command that tells AmigaDOS to make all the changes permanent on the disk.
  4419. BLOCK2TEXT
  4420. If you decide you don't want to use BLOCKs, we don't, you can convert your BLOCK file to a normal TEXT file.  This will let you use normal text editors like Textra and to use Amiga DOS commands like TYPE.  A facility has been provided to do that.  It is in the file JDEV:BLOCK2TEXT.  To convert a file called  PROJECT.blk to a file called PROJEECT.txt, enter:
  4421. INCLUDE JDEV:BLOCK2TEXT
  4422. BLOCK2TEXT PROJECT.blk PROJECT.txt
  4423.  
  4424. 15 -      BLOCK Environment
  4425.  
  4426.     BLOCK Environment    15 -  
  4427.  
  4428.  
  4429.  
  4430.  
  4431.  
  4432.  
  4433. Chapter 16
  4434. Precompiled Modules      
  4435. General Information about Modules    
  4436. What are Modules?
  4437. Perhaps the best way to describe the MODULE facility is to describe some of the situations in previous JForth releases it was designed to improve upon...   
  4438. 1.  In earlier JForths, all required include files (.j) had to be pre-compiled and resident in the dictionary in order to use them.   
  4439. 2.  In earlier JForths, the assembler had to be pre-compiled and resident in the dictionary in order to use it.   
  4440. 3.  In earlier JForths, the disassembler had to be pre-compiled and resident in the dictionary in order to use it.   
  4441. In each, significant dictionary area is used up by definitions that are only occasionally required; this space is also taken in all SAVEd-FORTHs...duplicated in each one.   
  4442. The MODULE facility allows us to save these sections of dictionary in disk-resident files, and provides a versatile interface to them.  Virtually no space is needed in the normal development image, yet at any time, the saved binary module may easily be read and 'hooked in', providing full access to the definitions it contains.  Just as easily, the module may later be 'unhooked', restoring the dictionary to its previous state.   
  4443. When the 'piece of dictionary' is 'hooked in', the VLIST (or WORDS) command will display it's names in keeping with the dictionary location at which they are physically linked in.   
  4444. Modules are generally only useful with large, 'execute-only' routines (such as the JForth assemblers and disassembler) and data definitions (compiled '.j' header files); these services are implemented as modules in JForth, as released.   
  4445. The purpose of this document is to describe these services such that the JForth user can quickly benefit from their use.  Also discussed are the few restrictions placed on source files destined to be saved as modules, if you wish to create your own.   
  4446. Modules and SAVE-FORTH  
  4447. A given module is compatible with all SAVE-FORTHed images that are identical at least from that module definition on down.  All the standard JForth modules are automatically created when the system is generated, so as long as you have not changed any JForth system functions, the supplied set of mod: files should always work for you.  
  4448. If you change something in the JForth system, and regenerate com:JForth, you simply answer Yes to the question dealing with module support when prompted during the rebuild process.  All mod: files will be regenerated.  Your task will then be to recompile your own application-specific JForth programs and SAVE-FORTH each one.  (Alternatively, you could save a copy of the mod: directory with each image, then re-assign mod: as appropriate).
  4449. Technical Notes on Modules    
  4450. 1.  The Module service provides a means of allocating a block of memory of a given size, and then shifting subsequent compilation to that area (instead of the normal, JForth-resident dictionary).   
  4451. 2.  When the program is finished compiling, compilation is returned to the resident dictionary.  However, the linked-list of Forth words now 'jumps' to this non-contiguous area and follows the definitions created by the file.  The last of these definitions will point again to the normal dictionary, to the word immediately preceding the word that 'jumped'.   
  4452. 3.  Fully compiled, the external memory is then 'unhooked' from the link list and saved to a file.  When again read from disk, the reverse process occurs...the existing link-list is broken and the binary module is 'hooked-in'.   
  4453. The benefits realized are multiple:  
  4454. * The saved utility is made available in a matter of seconds, a great improvement over the time it would take to compile it.  
  4455. * The program component does not occupy any contiguous dictionary area, even when loaded.  
  4456. * Saved images do not contain large, duplicate sections of program, increasing effective disk capacity.  
  4457. * If the utility is never called, it doesn't use any system resources (memory, dictionary search-time, etc.).  
  4458. JForth versions 1.3 and 2.0 look for all MODULES in whatever directory you have ASSIGNed the nickname 'mod:' to.  "JForth:assigns" defines it as "JForth:modules".   In JForth 3.0, additional flexibility is added to the GETMODULE and SEALMODULE functions, described below.
  4459. It is important to note that, other than .J structure-type files, module definitions may NOT BE DIRECTLY REFERENCED BY OTHER DEFINITIONS!  In other words, they may not be directly called by other programs.  The JForth compiler will not compile a reference to a routine outside of the normal dictionary, so you will be notified if you inadvertantly attempt it.  Techniques for programmatically accessing module definitions are described ahead (see WILLGET and WILLHIDE).   
  4460. Using the Assembler and Disassembler Modules  
  4461. The assembler (JU:FORWARD-ASM, which includes the RPN assembler) and disassembler (JU:DISM) have been provided as pre-compiled modules in the default MOD: directory.  Their names are MOD:ASSEM.MOD and MOD:DISASSEM.MOD, respectively.   
  4462. Both have been implemented transparently such that the module is automatically loaded at the first invocation of any of a specific set of words.  For example, the command:   DEF SWAP will load the disassembler module if necessary, and disassemble the code for SWAP.  The disassembler module will then remain linked in and available until specifically released by the programmer.   
  4463. The following words will automatically invoke the assembler module:   
  4464. CODE  ;CODE  ASM 
  4465. The following words will automatically invoke the disassembler module:   
  4466. DEF  DISM  RELDISM  RISM  ADISM  DISM-DONE?  DISM-WORD? 
  4467. INIT-DISM  DISM-CYCLES    DISM-NAMES DISM-ORIGIN .REGNAMES?
  4468. SHOW-CYCLES
  4469. Using other Modules     
  4470. This section describes the words used to directly manage the loading, usage, and unloading of a given module.   
  4471. A particular defined MODULE will always be in one of 3 possible states. The first state exists when the JForth image is initially booted (or anytime COLD is executed)...   
  4472. 1.  DETACHED... The module has not been read or was purged.  No Amiga memory is allocated for it.  If the module defines a vocabulary, it is not visible in this state.   
  4473.     The function:    GETMODULE <modulename>   enters the next state, when something in the module is needed...   
  4474. 2.  LOADED .... GETMODULE <modulename> will read the module from disk into a memory area that has been allocated outside of the JForth image.  It will be linked into the dictionary FIND path and its definitions (including its one possible vocabulary) will be accessible.   
  4475.     When the immediate need for the module is gone, it may be desirable that it not slow down the FIND process until needed again;  the module may be 'put away' temporarily with the following command:   HIDEMODULE <modulename>. (This is less of a consideration if the HASHed vocabulary search is in effect.)  
  4476. 3.  HIDDEN .... HIDEMODULE <modulename> will unlink the modules definitions from the dictionary FIND path, but the module remains in the memory area that has been allocated outside of the JForth image.  Its definitions (including its one possible vocabulary) are not accessible; but can be quickly made so with GETMODULE <modulename>, without re-reading from disk.   
  4477. The programmer, at any time, may return to the DETACHED state, reclaiming all memory used by the module.  The DETACHMODULE <modulename> is provided for this purpose.   
  4478. A fourth (FORTH?) command:  .MODULES  is provided to display the status of all defined modules.  Status is also displayed by the MAP command.   
  4479. Note that all normal JForth words (FILE?, VLIST etc.) operate normally on module definitions, once GETMODULE has loaded them.   
  4480. NOTE: The 3.0 versions of GETMODULE and SEALMODULE will accept one device-type specifier preceeding the module name (full pathnames are not supported).  Examples of the legal JForth 3.0 syntax for these commands include:
  4481. SEALMODULE RAM:MyModule 
  4482. GETMODULE RAM:MyModule 
  4483. SEALMODULE devs:MyOtherModule
  4484. GETMODULE devs:MyOtherModule
  4485. Files in INCLUDES Module    
  4486. The following '.j' files have been compiled into the released version of MOD:INCLUDES.MOD...   
  4487. ji:intuition/intuition.j 
  4488. ji:intuition/intuitionbase.j
  4489. ji:graphics/rastport.j 
  4490. ji:graphics/text.j 
  4491. ji:graphics/regions.j 
  4492. ji:exec/interrupts.j 
  4493. ji:exec/libraries.j 
  4494. ji:exec/execbase.j 
  4495. ji:libraries/dos.j 
  4496. ji:libraries/dosextens.j 
  4497. ji:devices/narrator.j 
  4498. ji:graphics/sprite.j 
  4499. ji:workbench/workbench.j 
  4500. ji:workbench/startup.j 
  4501. Creating a Custom Module    
  4502. The best candidates for new modules are custom structure definitions or larger utilities such as the Assembler or Disassembler.  These programs are usually INTERPRETED and EXECUTED, rather than called from other programs. Nonetheless, the ability to support a limited programmatic  interface is provided.   
  4503. Programs that are destined to become modules must conform to the following restrictions:  
  4504. 1.  The compiled program may not exceed 32K.  This restriction does not apply, however, if the module contains ONLY compiled '.j.' structure-based definitions.  Modules of this type may be of any size.   
  4505. 2.  No address of any component within the module may be saved within a variable, array, or any other type of storage element.  This includes DEFER and GLOBAL-DEFER children or routines which will be used as vectors for such; these may NOT be defined within modules.   
  4506. 3.  The use of ' is limited to ONLY those words that are inside the standard JForth dictionary.  For example:  
  4507. : NOOP-CFA   ' NOOP  ; 
  4508. is legal within a module, because the word NOOP is in the normal dictionary.  However:  
  4509. : NOOP2  ; 
  4510. : NOOP2-CFA  ' NOOP2  ; 
  4511. is incorrect since NOOP2 would be resident in the module.   
  4512. 4.  The module may define, at most, one VOCABULARY and it must tree from the FORTH vocabulary level.   
  4513. 5.  Do not define USER variables within a module...use normal VARIABLEs instead.   
  4514. The convention in effect for defining the standard modules is to create one source file, which, when INCLUDEd, will create the module definition and .MOD file pair.  For example, the file to define a module for a calculator utility and create the .MOD file would be called MAKECALC and would look something like:  
  4515. \ Create MOD:CALCMOD.MOD from XX:CALC.F (the source file) 
  4516.  
  4517. MODULE CALCMOD   \ define the module in the dictionary 
  4518.  
  4519. 4 MAKEMODULE CALCMOD   \ allocate 4K memory & 
  4520.                        \ shift compiling to there 
  4521.                        \ CRASH if not enough mem! 
  4522.  
  4523. INCLUDE XX:CALCMOD.F   \ compile the source file 
  4524.  
  4525. cr ." Writing MOD:CALCMOD.MOD" cr cr   \ nice message 
  4526. SEALMODULE CALCMOD                     \ write the file, 
  4527.                                        \ will be < 4K 
  4528. DETACHMODULE CALCMOD                   \ cleanup 
  4529. At this point, if a transparent interface (such as DEF and ASM use) is desired, a WILLGET command must be entered for each word that should automatically load and call the module.  The format of this command is:  
  4530. WILLGET <module-name> <function-name> 
  4531. where:     <module-name> is the same name as entered for the MODULE and 
  4532.         <function-name> is the name of the word in  the module to be executed.  
  4533. For example, if the main entry point for the above calculator program is called CALC, one more line in the file will be handy...   
  4534. WILLGET CALCMOD CALC 
  4535. will cause the word CALC to automatically load the module, then find and execute the word CALC within it.  This is the method for gaining programmatic access to the contents of a module.  Note that while even the names of words defined as VARIABLEs, CONSTANTs and STRUCTures may be specified in the WILLGET command, a VOCABULARY name cannot.  
  4536. A variant of WILLGET is provided which operates identically, except that words defined with it will HIDEMODULE when they finish execution.  It's usage...
  4537. WILLHIDE <module-name> <function-name> 
  4538. For further examples of creating MODULEs, refer to JF:MakeASSEM, JF:MakeDISASSEM and JF:MakeINCLUDES. 
  4539. If a transparent WILLGET interface to the module is not desired (or reasonable, as in the case of the INCLUDES module), the GETMODULE <modulename> command must be used to gain access to the module definitions.
  4540. WARNING:  You cannot Clone a program that calls routines in a module in any way, even via a defined WILLGET interface.
  4541. 16 -      Precompiled Modules
  4542.  
  4543.     Precompiled Modules    16 -  
  4544.  
  4545.  
  4546.  
  4547.  
  4548.  
  4549.  
  4550. Chapter 17
  4551. Miscellaneous Development Tools
  4552. Command Line History     
  4553. Since AmigaDOS 1.3, Amiga users have grown accustomed to the convienience of command line history, the feature in the SHELL that allows you to scroll through previous CLI commands using the arrow cursor keys.  Since this feature is only present in the CON: device (in AmigaDOS 1.3, the NEWCON: device), and JForth uses RAW: Amiga windows (to aquire single keystrokes for KEY), this feature was not automatically available.  We decided, therefore, to add our own command line history that is similar to the Shell history.  We also added the capability of loading the function keys with your own custom commands.   
  4554. Using the Cursor Keys    
  4555. [Note: Special keys are marked in this text by angle brackets. For example, <CR> , <HELP> , <UP-ARROW> , and <F7> all refer to single keys and not strings.]  
  4556. The History feature should be present in the normal JForth image.  To test this, hit the <HELP> key.  You should see a list of function key assignments.  If it is not loaded, enter the following:  
  4557. ^X  (to clear characters from <HELP> key.
  4558. INCLUDE? HISTORY JU:HISTORY
  4559. The PANIC.BUTTON key <shift-F1> is for use if the Forth Outer Interpreter gets messed up from a program error.  If you cannot enter valid commands at the keyboard without getting an error message, try the PANIC.BUTTON.  It tries to "simplify" and reset the environment, hopefully giving you a last chance to enter Forth and see what went wrong.  History will be automatically turned on when loaded.  Now enter the following lines:  
  4560. 23 45 67 
  4561. SWAP .S 
  4562. DUP . CR
  4563. Now use the <UP-ARROW> and <DOWN-ARROW> keys to scroll through these previous commands.  At any time you can use the <LEFT-ARROW> and <RIGHT-ARROW> keys to move within a line for editing.  If you hold the shift key down while hitting <UP-ARROW> you can search back for lines that start with the same string as the current line.  For example, enter the following:  
  4564. <CR> 
  4565. SW<SHIFT+UP-ARROW>
  4566. You should now see the line that started with SWAP.  Shift left and right arrow will move you to the beginning and end of the line respectively.   
  4567. If you hit <HELP> you will see a list of commands available on the function keys.  Notice that some of the commands, like "INCLUDE" have quotes around them.  This means that they will be inserted into the input stream.  Try these out.   
  4568. Wouldn't it be nice if you could easily distinguish between the text you entered and what the computer output.  You can make your input text be drawn in color 3 by entering:  
  4569. HIGHLIGHT-INPUT ON 
  4570. CR ." Hello"  ( in a new color )
  4571. You can use Preferences to change these colors if need be.   
  4572. Have you ever entered a great Forth word on the keyboard and wished you had done it in a file.  You can use LOGTO to save the past keyboard commands into a file.  Enter:  
  4573. INCLUDE? LOGTO JU:LOGTO
  4574. LOGTO RAM:SAVEIT 
  4575. HISTORY 
  4576. LOGEND
  4577. Now in the CLI enter:  
  4578. TYPE RAM:SAVEIT
  4579. Note: History will be disabled in a Cloned Application because it is primarily intended as a development tool.  Also many Cloned programs use the CLI which already has its own History.  If you want to use it in an application, use a RAW: window for your I/O, and remove the definition of KH.EXPECT from CL:REDEFS.F then recompile Clone.  The entry in the REDEFS.f file is what disables it when cloned.   
  4580. How History Works     
  4581. HISTORY.ON installs a new function into the deferred word EXPECT.  This new EXPECT handler performs it's own backspacing, cursor handling, etc.  It uses ANSI commands from JU:ANSI to move the cursor and to parse command keys that are hit.  As commands are entered they are added a list of commands stored in a byte array.  The buffer contains lines with count bytes at each end of each string.  This makes it easier to go back and forth in the list.   
  4582. History Glossary      
  4583. These commands are part of the JForth History feature.   
  4584. $>EXPECT ( $string -- , command history insert string )  
  4585. Place a string in the EXPECT buffer.  This is used when building function key words that put a string in the input stream. For example, "INCLUDE" which is on <F1> uses this.  To add FORGET to <F8> enter the following:  
  4586. : "FORGET"  ( -- , insert FORGET into input ) 
  4587.     " FORGET " $>EXPECT  ( notice space after last letter )
  4588. ' "FORGET" 8 FKEY-VECTORS ! 
  4589. See also FKEY-VECTORS .   
  4590. HIGHLIGHT-INPUT ( -- addr , make user input different color )  
  4591. Set this variable to TRUE to echo your input in color 3. Output from JForth will be in color 1.   
  4592. HISTORY  ( -- , print previous commands )  
  4593. HISTORY# ( -- , print history with numbers for XX )  
  4594. HISTORY.ON  ( -- , turn on history buffer and function keys )  
  4595. HISTORY.OFF  ( -- , turn off history and function keys )  
  4596. FKEY-VECTORS ( key# -- addr , jump table for function keys )  
  4597. This is an array that holds CFAs for the 10 function keys.  Here is an example of loading a function key with a function.   
  4598. : STATE? ( -- , NO stack activity allowed ) 
  4599.     >NEWLINE ." State = " STATE ? CR 
  4600. \  Assign STATE? to function key 7 
  4601.   ' STATE? 7 FKEY-VECTORS ! 
  4602. \ Now test it by hitting <F7> while compiling.  
  4603. : FOO ( -- , start compiling ) 
  4604.     ." Hello<F7> Fred" CR ; 
  4605. <HELP>  ( see it in list ) 
  4606. If you want to assign a function to a shifted function key, add 10 to the key#.  Thus if you had used 17 instead of 7 in the above example, You could hold down <SHIFT> then hit <F7> to see the value of STATE.   
  4607. KH_HISTORY_SIZE ( -- size , size in bytes of buffer )  
  4608. If you would like a bigger history buffer, edit the file JU:History and change the constant KH_HISTORY_SIZE to a bigger value.  Then regenerate COM:JForth as described in Chapter 12, System Internals, in the section labeled How to Generate a New JForth System.   
  4609. TAB-WIDTH ( -- addr , variable containing TAB width )
  4610. When a TAB character is entered, a number of BLANK characters are inserted in its place so that the cursor will be at a multiple of TAB-WIDTH.
  4611. XX  ( line# -- , execute previous line )  
  4612. Use HISTORY# (which, by default, is assigned to a function key) to see a list of previous commands with their numbers.  To execute a previous command, just pass that number to XX .  Once filled, the oldest command lines are lost from the end of the buffer as new command lines are added.  
  4613. Vocabularies      
  4614. Vocabularies provide a way to group words that are to be used in a specific context.  Examples within JForth are the ASSEMBLER vocabulary and the DISASSEMBLER vocabulary.  Within the ASSEMBLER vocabulary are words like NOT , and SWAP , that are 68000 opcodes.  These obviously conflict with existing Forth words.  By specifying which vocabulary you are using, one can avoid any ambiguity.   
  4615. Vocabularies can also be used to speed up compilation by temporarily removing a group of words that don't need to be included in the dictionary search, but this will provide benefit only if the HASHed dictionary search is not in effect.  JForth, as released enables the HASHed search.   
  4616. One can specify the order in which to search a set of vocabularies.  JForth uses a CONTEXT stack to determine this order.  The system is initialized at cold to:  
  4617. FORTH ROOT 
  4618. This means that JForth will search FORTH, and then ROOT, for any word typed in or encountered while compiling or interpreting.  FIND is the word that performs this search.  You can display the search order at any time using ORDER .  At COLD this will display:  
  4619. Searching (CONTEXT) : FORTH       ROOT 
  4620. Extending (CURRENT) : FORTH 
  4621. The first line shows the entire search path used by FIND on words that are encountered from the keyboard or a file.  These are called the CONTEXT vocabularies, because they define the CONTEXT in which the input stream will be INTERPRETed.   
  4622. The CURRENT vocabulary is that vocabulary to which new words will be added to as they are compiled, a process also known as 'extending' the vocabulary.   
  4623. Vocabulary Tutorial      
  4624. Before we begin exploring vocabularies, lets reset the search order so that we start from a known state. Enter:  
  4625. ONLY ROOT FORTH 
  4626. ORDER 
  4627. Now let's create a vocabulary called MUSIC that we can place MUSIC related words in.  Enter:  
  4628. VOCABULARY MUSIC 
  4629. ORDER 
  4630. Notice that the MUSIC vocabulary is not automatically placed in the search order.  We can add this VOCABULARY to the search order using ALSO. Enter:  
  4631. ALSO MUSIC 
  4632. ORDER 
  4633. We now would like any music related words we define to be added to the MUSIC vocabulary.  For this to happen, the CURRENT vocabulary must be set to MUSIC.  DEFINITIONS will copy the top of the CONTEXT stack to CURRENT.   
  4634. : FOO ." Regular old FOO!" CR ; 
  4635. DEFINITIONS ORDER 
  4636. FOO will have been defined in the normal FORTH dictionary because it was before DEFINITIONS.  Everything after will go into the MUSIC vocabulary. Now let's define some music stuff.   
  4637. : NOTES ." fa la la!" CR ; 
  4638. : SYMPHONY ." da da da duuuuh!" CR ; 
  4639. : FOO NOTES SYMPHONY ; 
  4640. FOO 
  4641. The musical FOO is executed because MUSIC is first in the search order.  We can get the old FOO by dropping MUSIC from the top of the CONTEXT stack.   
  4642. PREVIOUS DEFINITIONS ORDER 
  4643. FOO 
  4644. Vocabulary Glossary      
  4645. ALSO  ( -- , dups the top of the vocabulary stack)  
  4646. Usually this is followed by a vocabulary call as in: 
  4647. ALSO ASSEMBLER
  4648. This will cause the ASSEMBLER vocabulary to be added to the search order, first in the list.
  4649. DEFINITIONS  ( -- )  
  4650. Sets the current vocabulary to the top vocabulary on the context stack.  This results in new definitions being added to whatever vocabulary is first in the search order.  
  4651. MAXVOCS  ( -- n , maximum number of vocabularies allowed )  
  4652. JForth allows 32 different vocabularies to be defined.   
  4653. ONLY  ( -- , reinitialize context stack to Forth and ROOT )  
  4654. If followed by a vocabulary name, the search order becomes that vocabulary, then ROOT, and no others.   
  4655. ORDER  ( -- , print CONTEXT stack and CURRENT )  
  4656. Displays the current search order, left to right.   
  4657. PREVIOUS  ( -- , drops the top item off the vocabulary stack)  
  4658. Removes the first vocabulary in the search order, the one 'just below' becomes firstmost.   
  4659. SEARCH-CURRENT ( -- addr , variable to control search )  
  4660. FIND checks SEARCH-CURRENT to decide whether to search the current vocabulay after it searches all the context vocabularies.  JForth default is to set SEARCH-CURRENT OFF.  (It is particularly useful to not search CURRENT when compiling new Forths or Forth-like packages, as a cross-compiler application might do, where execution of a target word would crash the host system).   
  4661. VOCABULARY  ( <name> -- )  
  4662. Define a new vocabulary called NAME.  When this vocabulary is executed it will place itself at the top of the CONTEXT search order.  Vocabularies are not IMMEDIATE.   
  4663. Vocabulary Internals      
  4664. VOC-LINK points to the linked list of vocabularies starting with the most recently defined.   
  4665. Current JForth vocabulary structure:   
  4666. voc-link@:    ( link to other vocabularies ) 
  4667. voc-latest@:  ( point to last word in vocabulary ) 
  4668. The structure of vocabularies may be changed in the future.  Therefore, use the words we have supplied for moving around the vocabulary structure:  
  4669. VLINK>           
  4670. VLINK>VLATEST 
  4671. VLATEST>VLINK 
  4672. VLINK is the linked list address for a particular vocabulary.  VLATEST is the address of the vocabulary pointer to the top of its linked list of words.  Each vocabulay list of words is terminated with zero in the LINK field.   
  4673. Here is an example of using these words.   
  4674. VOC-LINK @ .    ( get pointer to last vocabulary ) 
  4675. VOC-LINK @ VLINK>VLATEST @ ID. ( last word in vocab) 
  4676. VOC-LINK @ VLINK>' >NAME ID.  ( name of vocab ) 
  4677. VOC-LINK @ @ VLINK>' >NAME ID.  ( print next vocab ) 
  4678. Look at the VOCS source file if you want to delve deeper.   
  4679. SHOWHUNKS - for Analyzing Amiga Binary Files 
  4680. JU:SHOWHUNKS may prove helpful to anyone that needs to get 'into' object files, libraries, executables, any file that conforms to the Amiga Binary Format.   
  4681. Using the com:JForth image, type:  
  4682. INCLUDE JU:SHOWHUNKS 
  4683. You may be asked about INCLUDEing JU:DISM while this program compiles.  If you want to display CODE hunks as disassembled 68000 code (instead of just HEX numbers), instruct the program to use the disassembler.  
  4684. Also, if there is not enough dictionary space for JU:DISM, you will be informed as such.  
  4685. When its done compiling, try:  
  4686. SHOWHUNKS C:DIR 
  4687. What you'll be looking at is the CLI 'dir' command file.   
  4688. CODE_LIMIT is a variable it uses to tell what the largest HUNK_CODE it should display, in cells.  Its default value is 100,000 (displays anything less than 100,000 bytes)...which should show you most, if not all, programs you ask for.  If you wish to lower this amount to mask out the larger hunks, just enter:
  4689. 100 CODE_LIMIT !  \ only display CODE_HUNKS less than 100 bytes in size
  4690. The final interesting thing about this file is that it uses an execution array to perform specific actions on each type of hunk; you may define your own 'array' of vectors (cfa's)...  one for each HUNK_TYPE (see the table in the source for examples)...put the base address of the table in ACTIONSARRAY then type:  
  4691. PROCESSHUNKS <FILENAME> 
  4692. See the definition of SHOWHUNKS, last thing in the file.   
  4693. Yes, I suppose you COULD write your own Loader/Linker with PROCESSHUNKS...   
  4694. JForth Optimizing Compiler Extensions
  4695. This utility extends the JForth Professional V2.x and V3.x compiler such that it will, under certain circumstances, produce smaller, tighter and faster code. 
  4696. How to use the Optimiser 
  4697. 1. Load the com:JForth image. 
  4698. 2. Compile the file 'jdev:opt.f'. 
  4699. 3. From the keyboard, type:  OPT   followed by the RETURN key. 
  4700. At this point the optimizer is installed, and definitions which are loaded on top of this image will be optimized where possible. 
  4701. Note that the supplied 'jdev:opttest.f' file illustrates the improvement that can be realized.  To run this test... 
  4702. 1. Deactivate the optimizer by entering:  OPTOFF 
  4703. 2. Run the test by entering:  INCLUDE jdev:opttest.f Note the times that are printed to screen 
  4704. 3. Activate the optimizer by entering:  OPT 
  4705. 4. Run the test again by entering:  INCLUDE jdev:opttest.f Compare with the previous results. 
  4706. Optimizer Glossary 
  4707. OPT    ( -- ) 
  4708. Activates the optimizing extensions by setting INTERPRET vector. 
  4709. NOOPT  ( -- ) 
  4710. De-activates the opimizer, reverts the compiler behavior to normal by restoring the INTERPRET vector. 
  4711. OPTON  ( -- , same as OPT ) 
  4712. OPTOFF ( -- , same as NOOPT ) 
  4713. Caveats 
  4714. 1. Dictionary size - this version of the optimizer requires  about 7-8K of dictionary.  Since it would take a very large application to save this much room due to optimizations, the most benefit is felt in CLONEd programs. 
  4715. 2. The keywords OPT and OPTON (same function, different name) will only operate as expected if typed from the  keyboard (vs. INTERPRETed from a file). 
  4716. 3. I believe the JU:DEBUGGER utility and OPT do not co-exist well; they tend to 'un-install' each other.  If  you need to use the debugger, just OPTOFF before starting  your debug compile. 
  4717. 4. Don't FORGET the optimizer while it's installed!!!!  (IF.FORGOTTEN doesn't help here!) 
  4718. Technicals (for those who care) 
  4719. OPT checks for sequential compilation of a subset of JForth words, specifically (in this version)... 
  4720. +       -       DROP   SWAP    DUP     ROT     -ROT
  4721. 1+      1-      2+     2-      I       C@      C!
  4722. @       !       OVER   2DROP   >R      R>      AND
  4723. OR      NIP     2DUP   R@      CELL+   CELL-   CELLS
  4724. 2*      2/
  4725. LITERAL numbers and CONSTANTS are also optimized. 
  4726. If OPT finds that, while compiling, any sequence of at least 3 of these words is encountered, it creates code that will, at runtime, cache stack items in the CPU data registers.  D1, D2, D3, D4 and D7 are utilized for this purpose (permitting up to 5 stack items to be cached).  The registers are not blindly loaded; rather, a "load as needed" algorithm is implemented. 
  4727. Let's consider the sequence:   SWAP ROT + 
  4728. The normal JForth compiler (w/ MAX-INLINE set to 12) will produce... 
  4729. move.l  (dsp),d0       code for SWAP...
  4730. move.l  d7,(dsp)             "
  4731. move.l  d0,d7                "
  4732. move.l  $4(dsp),d0     code for ROT...
  4733. move.l  (dsp)+,(dsp)         "
  4734. move.l  d7,-(dsp)            "
  4735. move.l  d0,d7                "
  4736. add.l   (dsp)+,d7      code for +
  4737. The code produced by the new compiler for the same high-level statements will be... 
  4738. move.l  (dsp)+,d1
  4739. move.l  (dsp)+,d2
  4740. add.l   d1,d2
  4741. The first two instructions in the optimized example simply load stack items into the CPU, where the '+' opcode (add.l) processes them. 
  4742. What happened to the SWAP and ROT operations?  Well, the optimizer factors them in at COMPILE time.  For example, no code needs to be actually created for a SWAP because the new compiler keeps track of which register currently holds the top item, where any second is, etc.  Therefore, after a SWAP, the compiler will simply create opcodes that reference whichever register holding the correct data.  
  4743. It should be pointed out that the new compiler does not specifically look for the sequence 'SWAP ROT +' to do this... it finds ANY SEQUENCE (of 3 or more) of the above words and puts together optimized code.  This means that optimized code will be created if 'SWAP ROT <anything>' is compiled, as long as <anything> is in the above list. 
  4744. Note that the above code leaves register D2 holding the topmost stack-item and register D7 containing the second one.  This is radically different from the normal JForth register usage (D7 holds TOP-OF-STACK, other items in memory on data stack), but as long as we continue to compile words in the above list, the new compiler will account for the non-standard parameter locations. 
  4745. However, if the new compiler finds that no more optimizations can be done, it will put things back to normal by 'flushing the cache'. For the above example, it would do this by appending the following code... 
  4746. move.l  d7,-(dsp)      push out second item...
  4747. move.l  d2,d7          put top item in normal place
  4748. This code is specific to this example; other combinations will probably leave the top item in other registers (or cache a different number of items) and will require different but similar cleanup code.
  4749. PROFILE - Performance Analyser 
  4750. Ask most programmers and they will tell you that "most programs spend 80% of their time in 20% of their code." If you are going to optimize a program it would be nice to know which 20% to optimize.  PROFILE is a performance analyser that will interrupt your code while it is running and keep track of where it is spending its time. 
  4751. To compile PROFILE, enter: 
  4752. INCLUDE? PROFILE JDEV:PROFILE
  4753. Now lets write a small program and analyse its performance. Enter in a file and INCLUDE the following: 
  4754. ANEW TASK-TESTPRO
  4755.  
  4756. : MOOP      12 0 DO LOOP ;
  4757. : BOOP     123 0 DO LOOP ;
  4758. : GOOP       1 0 DO LOOP ;
  4759.  
  4760. : FOOP
  4761.     0 DO MOOP BOOP GOOP
  4762.     LOOP
  4763. ;
  4764. The words MOOP BOOP and GOOP will take different lengths of time to execute because they loop different numbers of times. Lets pretend we don't know which one is the longest.  PROFILE works like MEASURE. It will analyse whatever follows on the command line.  Enter: 
  4765. PROFILE  5000 FOOP
  4766. You will see a short report on how PROFILE is setup then a message that PROFILE has begun. PROFILE is now running your program and interrupting it occasionally.  During the interrupt it looks on the return stack to see where the program was executing. To keep track of where this was, PROFILE divides your program into slots.  The short report tells you the starting and ending address of the slots and the size of each slot. When an interrupt occurs while your program was in a slot, that slot's counter is incremented. When PROFILE is finished, it analyses the slots and reports on which slots took the most time. It will give you the slot number, its address range, how many interrupts fell into that slot, the percentage of total time, and the percentage of the slots analysed. Check the number of interrupts that you collected to make sure you got enough, at least 10 in the least reported slot. Your program should probably execute for at least a few seconds. On a fast Amiga you may have to do more loops like 20,000 instead of 5,000. 
  4767. Look at the report from PROFILE. Look at the leftmost column to find the slot number with the highest percentage. Lets assume, for example, that it is 106. To find out what words are in that slot, enter: 
  4768. 106 PF.WHO  \ or whatever slot you want
  4769. Notice that probably all the words in TESTPRO are in that slot. To narrow our analysis down, enter: 
  4770. 106 PF.ZOOMIN
  4771. This will zoom in to just the words in slot 106.  Now rerun PROFILE. 
  4772. PROFILE  5000 FOOP
  4773. Look to see, what slot is now the highest and use PF.WHO to see what words are in there.  You will probably find that we are spending most of our time in BOOP which is no surprise. 
  4774. Remember the first time we ran PROFILE. There was another slot that showed significant activity. Let's zoom back out and rerun PROFILE to see which one that was. 
  4775. PF.ZOOMOUT
  4776. PROFILE  5000 FOOP
  4777. Use PF.ZOOMIN like before, rerun PROFILE. then use PF.WHO to find the culprit.  It will probably be ((?DO)) which is a primitive part of a DO LOOP. 
  4778. PROFILE - Glossary 
  4779. PF.ZOOMIN  ( slot# -- , adjust slots to detail a slot )
  4780. PF.ZOOMOUT ( -- , adjust slots to full dictionary )
  4781. PF.WHO     ( slot# -- , print what words are in that slot )
  4782. PF-INT-RATE ( -- addr , variable holding desired intrs/sec )
  4783. PF-%-REPORT ( n -- , threshold percentage to report slot )
  4784. PROFILE   ( <executable_forth_statement> -- )
  4785. PROFILE - Discussion 
  4786. The technique that PROFILE uses has some good and bad aspects. One problem that can occur is that if your program loops at the same rate as the interrupt occurs, you will always appear to be executing the same small piece of code. To prevent this, try changing the interrupt rate by setting PF-INT-RATE to a different value. Do not go above 1000 or you will bog down the system. 
  4787. There is another technique for profiling that does not use interrupts.  This other technique requires you to compile the program with special profiling code built in. The results can sometimes be more accurate, but program execution can be effected by the extra code.  Kernel words that are called in such a system are reflected in the times for the application level words that call them.  This may be desirable. A disadvantage of the other system is that execution within a word cannot be analysed.  Using PROFILE,  a single word can be analysed to see which part is slowest by zooming in. 
  4788.  
  4789. 17 -      Miscellaneous Development Tools
  4790.  
  4791.     Miscellaneous Development Tools    17 -  
  4792.  
  4793.  
  4794.  
  4795.  
  4796.  
  4797.  
  4798. Chapter 18
  4799. Amiga Libraries and Structures     
  4800. The Amiga is a treasure chest full of wonderful tools: high speed color graphics, pull down menus, speech devices, powerful system libraries.  This section of the manual tells you how to use JForth to open that treasure chest.  We will describe how to call Amiga Library routines and how to use Amiga structures.  We will then describe some of the special tools we have provided to make this easier.   
  4801. Amiga Libraries - Tutorial
  4802. The Amiga system software is organized into libraries that can be used by any program.  If you want to open a window, read a file, or draw a rectangle you need to call a library routine to do this.  The most often used libraries are DOS, which handles files and processes, GRAPHICS, which handles drawing lines, images, text, etc., INTUITION, which is used to control windows, screens, menus and gadgets, etc., and EXEC which controls the guts of the machine.   
  4803. Let's start by calling a DOS routine that waits for a given time.  Before we call any library routine we must first OPEN that library.  Enter:  
  4804. DOS? 
  4805. This will open the DOS library. If it is already open then nothing will happen.  (JForth always opens the DOS and EXEC libraries when it starts up but it doesn't hurt to call this again.) Any library that is known to JForth can be opened by calling a similar word, eg. GRAPHICS? or INTUITION? .   
  4806. We now need to know what arguments, or parameters, this function takes.  We should look this up in the DOS Developers Manual to find out everything about this routine.  But if you just want to see the argument list you can use ARGS to look them up.   
  4807. ARGS DOS_LIB DELAY 
  4808. ARGS will search through the "FD" files which contain information about the libraries.  It prints the argument list and its offset in the library.  The offset is handy for assembly language programmers.  If the Amiga asks you to insert the disk "FD:" don't worry.  It just means that you forgot to execute the ASSIGNS file.  This file tells JForth what directory to find other files in.  If you get this message, enter in the CLI window:  
  4809. EXECUTE JFORTH:ASSIGNS 
  4810. then hit the "Retry" button on the requestor.   
  4811. ARGS will tell you that the Delay function takes one argument, the TIMEOUT value.  If we look in the manual we will discover that this is expressed in 1/50ths of a second.  We will also discover that it does not return a value.  Routines that do not return a value are called "VOID".  Now that we know what we are calling, let's write a word that calls Delay.   
  4812. : Delay()  ( timeout -- , delay for timeout/50 seconds ) 
  4813.     CALLVOID DOS_LIB DELAY
  4814. ;
  4815. Notice that we put two parentheses at the end of the word name.  This is a JForth convention that indicates we are calling an Amiga library routine. The word CALLVOID word looks up the information about DELAY just like ARGS did.  Then it builds the code necessary to call that routine.  We can use the JForth word CALL for routines that do return a value.  Now let's test our word.   
  4816. 150 DELAY() 
  4817. This should cause a delay of about three seconds.  Pretty exciting? Don't worry.  Before long you will be opening windows and doing graphics.   
  4818. Passing Addresses to Library Routines   
  4819. JForth uses what are called relative addresses.  All the Forth words like @ and !, or variables, use an offset from the base of the JForth dictionary. This is so that the addresses will be the same every time you run JForth even though the actual Amiga addresses may be different.  This greatly simplifies most programming tasks.  If you are passing addresses to Amiga library routines, however, you will need to convert them to absolute 68000 addresses.  Luckily, this is very easy to do using >ABS which converts a relative JForth address to a 68000 absolute address.  Enter:  
  4820. ' DUP .HEX  ( relative address of DUP code ) 
  4821. ' DUP >ABS .HEX  ( actual absolute address )
  4822. Let's call an Amiga routine that requires some absolute addresses. Intuition has a function called CurrentTime that will set two variables to the current time.  We will need to pass the absolute addresses of those two variables.  Enter:  
  4823. VARIABLE SECONDS 
  4824. VARIABLE MICROS 
  4825. : CurrentTime() ( addr-seconds addr-micros -- ) 
  4826.     >ABS SWAP >ABS SWAP  ( convert both addresses ) 
  4827.     CALLVOID INTUITION_LIB CURRENTTIME 
  4828. : PRINT.TIME  ( -- seconds micros ) 
  4829.     SECONDS MICROS CurrentTime() 
  4830.     ." Seconds = " SECONDS @ .  
  4831.     ." , Micros = " MICROS @ . CR 
  4832. INTUITION?  ( open library! ) 
  4833. PRINT.TIME  ( test it ) 
  4834. Notice how the same word that calls the library routine does the address conversion.  That way you only have to pass the normal relative addresses. Whenever possible, try to only pass relative addresses between words.   
  4835. Now that you know how this works, I will show you a shortcut.  If you enter  
  4836. ARGS INTUITION_LIB CURRENTTIME 
  4837. you will see that the arguments are passed in A0 and A1.  These are Address registers, as opposed to Data registers like D0 or D1.  We can use a special form of CALL that will automatically convert any argument that goes into an address register.  This works fine with the GRAPHICS, EXEC, INTUITION and most other libraries.  Unfortunately DOS uses data registers to pass addresses (!) so we have to do the >ABS ourselves with DOS.   
  4838. Here is another way of defining CurrentTime() using this feature:  
  4839. : CurrentTime() ( addr-seconds addr-micros -- ) 
  4840.     CALLVOID>ABS INTUITION_LIB CURRENTTIME   ;
  4841. This will work even with a mix of address and data arguments.  Look at:  
  4842. ARGS GRAPHICS_LIB  DRAW 
  4843. We have been writing simple routines whose only function is to call an Amiga Library routine.  You could, of course, use CALL in any colon definition no matter how large.  We recommend, however, that you use these small "glue" routines to save space and produce more modular code.   
  4844. Getting Values from Library Routines   
  4845. Most Amiga Library routines return a value to the calling program.  If, for example, you open a window, the Intuition Library will return to you a pointer to a window structure.  You can use this pointer to get information about the window or to perform graphics operations on this window.  This pointer will be returned in absolute mode.  You should convert this to relative mode before passing it on.   
  4846. You could use >REL to preform this conversion.  A problem can occur, however, if Intuition passes you back a NULL, or zero, pointer.  This can happen if Intuition fails to open a window.  If you used >REL the NULL would get converted to a nonzero value.  You would then be unable to check the pointer to see if it is valid.  In this case, therefore, we should use IF>REL for our conversion.  It will only convert an address if it is nonzero.  Here is how you would call the OpenWindow routine.   
  4847. : OpenWindow() ( newwindow -- window ) 
  4848.     CALL>ABS INTUITION_LIB OPENWINDOW 
  4849.     IF>REL  ( convert window address )   ;
  4850. (There is an example of the use of this routine in the JForth Graphics toolbox that we will study later.)  
  4851. Accessing the Amiga Libraries  - Reference
  4852. With the installed JForth word set, all the standard Amiga 2.0 libraries are accessible, along with a few more:  
  4853. arp                    asl                  battmem
  4854. battclock              clist                commodities
  4855. console                cstrings             disk
  4856. diskfont               dos exec             expansion
  4857. gadtools               graphics             icon
  4858. iffparse               input                intuition
  4859. keymap                 layers               mathffp
  4860. mathieeedoubtrans      mathieeesingbas      mathieeesingtrans
  4861. mathtrans              misc                 potgo
  4862. ramdrive               rexxsyslib           romboot
  4863. timer                  translator           utility
  4864. workbench 
  4865. Opening Libraries
  4866. The JForth-recommended method for opening a library is to state the name immediately followed by a question-mark.  For example, at the startup of a program which will call both the graphics and intuition libraries, the programmer need only state 'GRAPHICS?' and 'INTUITION?'.  These words will open the library only once, regardless of how many times they are called.   
  4867. : MY-PROGRAM  ( -- ) 
  4868.     GRAPHICS?               \ opens graphics.library if needed 
  4869.     ...my-graphics-words... \ run application 
  4870.     -GRAPHICS    ;          \ close the graphics.library 
  4871. JForth opens two of these libraries for you, EXEC and DOS.  These libraries are ALWAYS open when the JForth development environment is up. While not an error, it is a null operation to execute either EXEC? , -EXEC, DOS? or -DOS.  They are provided only for compatibility reasons and the surrounding JForth environment will actually manage them.   
  4872. Your program may specify a particular version of a library by storing the desired version number in the user variable called LIBVERSION.  Otherwise, JForth will not care which version is found; any will suffice.  Note that, if version number IS important to you, it will have to be stated just prior to each library open operation.  This is because the variable LIBVERSION is automatically set to zero after each library is opened.
  4873. 36 LIBVERSION !  GRAPHICS? 
  4874. 36 LIBVERSION !  INTUITION?
  4875. The words that open libraries, such as GRAPHICS?, provide two types of behavior on an error; either to execute QUIT or not (in a CLONEd application, QUIT will exit the program) or not.  See the section Library Open Verification ahead for details.
  4876. Note: When a library is opened, it's absolute address is stored in the word called "name_LIB".  For example, if you opened the Intuition library, the Intuition library pointer would be stored in INTUITION_LIB .  This pointer points to INTUITIONBASE.  To get the address of INTUITIONBASE, enter:
  4877. INTUITION?
  4878. INTUITION_LIB @ >REL  ( get relative address of INTUITIONBASE)
  4879. The same technique can be used to get EXECBASE or other useful library bases.
  4880. Closing Libraries.
  4881. Closing libraries is similarly easy: library name preceded by a 'minus' sign.  The above example application, at termination, can cleanup the two libraries by executing:
  4882. -GRAPHICS
  4883. -INTUITION
  4884. Note that the '-NAME' words unconditionally close the library, They should, therefore, only be used when an application terminates.   
  4885. The 'exec' and 'dos' libs cannot be affected by these words. JForth maintains these libraries; the words '-DOS' and '-EXEC' are provided for compatibility reasons and have no code.   
  4886. Calling Amiga Libraries.     
  4887. Accessing a library is made easy by JForths 'call compiler'. The format for a system call is as follows:  
  4888. arg1 arg2 ... arg(N)   CALL   libname_LIB  FunctionName 
  4889.  
  4890. ARGs = the arguments in the same order as in the Amiga 
  4891.        technical reference manuals.  
  4892. 'Call'         = invokes the 'call-compiler' 
  4893. 'libname_LIB' = name of library followed by '_LIB' 
  4894.                 (lower case ok) 
  4895. FunctionName   = standard, full-text, Amiga name for the 
  4896.                  function.  
  4897. For example, the dos function 'Seek' is listed in the AmigaDOS Developer's Manual as follows:   
  4898. Seek( file, position, mode ) 
  4899. In JForth, a typical SEEK to the beginning of a file might appear:
  4900. : REWIND.IT  ( -- prev-position , rewind my file )
  4901.   ( file     position        mode   )
  4902.   MYFILE @       0      OFFSET_BEGINNING call dos_lib seek  ;
  4903. CALL builds all the necessary code to access the library.  It looks up in the "FD:" files to find out which parameters are passed, then calculates the offset of the routine in the library.  It then builds the code necessary to pull the parameters off of the stack, place them in the proper 68000 registers and call the routine.  CALL may only be used during compilation, for example, inside of a colon definition.  It cannot be used interactively from the keyboard.
  4904. CALL will normally return the contents of register D0 on the stack.  This is the way values are normally returned from the Amiga libraries.  Some library functions, however,  do not return a value, and some return two.  Others even return special values in the Status Register.  JForth provides words that instruct CALL to compile slightly different code for these situations.
  4905. Library Open Verification
  4906. VERIFY-LIBS  ( -- var-addr , IMPORTANT !!!!!)
  4907. If this variable is TRUE (which it is, by default), JForth will compile a check before every new library call to make sure that the library is open.  This can save you from crashing when you are first debugging a program and might forget to open a library.  Once you have your program debugged and are opening the necessary libraries properly, you should set this variable to FALSE and recompile.  Since your program will no longer be making these redundant checks, it will run faster.  Note:  CLONE will automatically remove these checks when generating a target image.
  4908. VERIFY-LIBS OFF   ( then recompile! )
  4909. LIB_QUIT  ( -- var-addr , JForth 3.0 and later )
  4910. By default, LIB_QUIT is set TRUE.  This will cause QUIT to be executed if an error occurs inside a library-opening word such as GRAPHICS?.  (Note that within a CLONEd standalone program, QUIT will cause the application to exit).
  4911. To prevent this, the program should set LIB_QUIT to false before every call to a XXX? word which will open a library.  For example...
  4912. LIB_QUIT off   INTUITION?
  4913. LIB_QUIT off   GRAPHICS?
  4914. To check if the library opened successfully, the program may check the contents of the XXX_LIB variable for a non-zero value.  For example...
  4915. LIB_QUIT off   ICON?
  4916. ICON_LIB @  ( -- lib-pointer / 0 )  \ will be 0 if error occured
  4917. CALL modifiers
  4918. When these words are used before CALL, they will affect the way that the Amiga Library call is compiled.  These modifiers only affect the next CALL then they are turned off.  In actuality these words are seldom used.  We have provided shortcut words that are described in the next section.  These modifiers are mainly used if you need several together, for example, RET:DOUBLE and RET:SR.
  4919. : SAMPLECALL  ( parameters... --  double sr )
  4920.     RET:DOUBLE  RET:SR  CALL MATHIEEEDOUBBAS_LIB IEEEDPMul  ;
  4921. AREGS>ABS  ( -- , tell CALL to convert addresses with >ABS )
  4922. When CALL looks up the parameters in the FD files, it knows which ones are addresses because they get put into address registers.  CALL can therefore automatically convert these addresses from JForth relative addressing to Amiga absolute addressing.  Warning! DOS passes address in data registers so use >ABS explicitly with DOS calls.  NULL addresses are preserved.
  4923. RET:DOUBLE  ( -- , tell CALL to return both D0 and D1 )
  4924. This is used when you want a 64 bit result. This is used extensively with the double precision floating point libraries.
  4925. RET:SR  ( -- , return Condition Codes from Status Register )
  4926. Some of the floating point routines pass back overflow and other flags in the Status Register.  This allows you to get those codes.  Warning!  Do not bypass this facility by calling MOVE-FROM-SR because this instruction is not legal on some 680x0 processors.
  4927. RET:VOID  ( -- , tell CALL not to return a value )
  4928. This will instruct the CALL operator to NOT compile the code to put the return value on the stack.
  4929. CALL shortcuts
  4930. We have provided some special versions of CALL that incorporate these modifiers.  These are used more often than using the modifiers directly.
  4931. CALL  ( ...parameters... <name_LIB> <function> -- result )
  4932. Normal call without modifiers.  Any addresses passed should have already been converted using >ABS.
  4933. CALL>ABS  ( ...parameters... <name_LIB> <function> -- result )
  4934. Just like CALL except parameters destined for address registers are converted automatically.  NULL addresses are preserved.
  4935. CALLVOID  ( ...parameters... <name_LIB> <function> -- )
  4936. Don't return anything.
  4937. CALLVOID>ABS  ( ...parameters... <name_LIB> <function> -- )
  4938. Combination of CALL>ABS and CALLVOID .
  4939. DCALL  ( ...parameters... <name_LIB> <function> -- double )
  4940. The DOUBLE returned occupies 2 stack cells.
  4941. As a convention, words that do little  more than call an Amiga library routine should have a () suffix placed on them.  These Forth words should have the same calling sequence as the Library routine. For example:  
  4942. : DELAY() ( #ticks -- , delay #ticks 1/50ths second) 
  4943.     CALLVOID DOS_LIB Delay
  4944. 100 DELAY() 
  4945. To find out what parameters a routine expects, you can use the ARGS facility. ARGS will search the '.fd' files and print the line that contains the parameter description.   
  4946. ARGS dos_lib seek   ( prints parameters for seek ) 
  4947. Adding Libraries.
  4948. The following section applies only if you wish to call a custom library, one not supplied with the original Amiga Workbench release.   
  4949. The library must be a normal Amiga Library that can be opened using OpenLibrary().  Examples are the ARP library, the Live video digitizer library, Bill Barton's MIDI library, and the AREXX library.  (You can also create you own libraries.  The details for this are in the Amiga technical literature, and beyond the scope of this discussion.)
  4950. Once you've installed your library in the Amiga OS by placing it your LIBS: directory, 'teaching'  JForth about it is easy, as illustrated in the following steps, which define a new library called 'GOODIES'.  Note that there is NO space between the ':' and the 'L' in this next line.   
  4951. :LIBRARY GOODIES  ( this creates GOODIES_NAME ) 
  4952.                  ( and GOODIES_LIB, used in  ) 
  4953.                  ( the following steps ...   ) 
  4954.  
  4955. : GOODIES?    GOODIES_NAME  GOODIES_LIB  LIB?  ; 
  4956.  
  4957. : -GOODIES    GOODIES_LIB   -LIB   ; 
  4958. These are the operatives you will use to open your library, in the same manner as that described above under 'Opening Libraries'.   
  4959. Finally, you will have to construct a 'function declaration' file for your new library that JForth can read and find the calling parameters.  This is an ASCII file that can be created with any popular editor and should be placed in the JForth logical volume 'FD:'.  Your new file should reside there, and should be similar in format to those which are Amiga-defined; use them as a model, but note the following:   
  4960. JForth does not require all of the info contained in a standard '.fd' file, so you needn't bother to build the entire text; the only required portions are:  
  4961. ##bias xx 
  4962. Function1(arg1name,arg2name)(arg1reg/arg2reg) 
  4963. Function2(arg1name,arg2name,arg3name)(arg1reg/arg2reg/arg3reg) 
  4964. The xx above equals the offset from library base for 1st call in list.   
  4965. For example...the 1st 3 required lines in the DOS_LIB.FD file are:  
  4966. ##bias 30 
  4967. Open(name,access-mode)(D1/D2) 
  4968. Close(file)(D1) 
  4969. If you were to type that file, you would see that there are more lines present; but these are all that JForth requires.   
  4970. Once you have compiled the ':Library' statement (along with the 2 opening and closing operators) AND installed a proper '.fd' file (in the logical volume fd: ) JForth will allow you to reference that library and its routines by name.   
  4971. Amiga 'C' Structure Interface    
  4972. Structures in the Amiga    
  4973. The Amiga uses "structures" to describe things like windows, screens, icons, fonts, bitmaps, tasks, etc.  A structure contains information about these things like width, color, type, etc.  All of this information is collected in one area that can be referred to by a single address.  Many of the important Amiga routines pass these addresses as a way of referring to windows, menus, etc.  Accessing the features of the Amiga requires you to be able to set and retrieve values in these structures.  JForth provides tools for accessing these Amiga structures and for defining new ones of your own design.   
  4974. Loading Structure Definitions from ".j" Files  
  4975. The data structures that the system uses are typically defined in a set of 'C' include files whose names end in ".h".  These files contain templates that describe how the data in a structure is arranged.  These files also contain the definitions of named constants.  A 'C' program that wants to reference these data structures includes the appropriate ".h" files.  For JForth programmers, a set of equivalent files has been created for inclusion in JForth programs.  These files have names that end in ".j". They reside in the logical volume "JI:".  To load the structures needed for the Serial device, you would enter:  
  4976. INCLUDE JI:DEVICES/SERIAL.J 
  4977. Loading Structure Definitions from Precompiled Modules  
  4978. Most of the structures that you will need have been precompiled for fast access.  They are stored in a module file called MOD:INCLUDES.MOD on the JForth disk.  To access these files you must first define the MOD: volume by executing the JForth:ASSIGNS file.  Please do this, if you haven't already,by entering in the CLI window:  
  4979. EXECUTE JFORTH:ASSIGNS 
  4980. Now you can enter, in JForth:  
  4981. GETMODULE INCLUDES 
  4982. This will link the structure definitions from the include files to your dictionary.  Please see the section on Modules for more information on how this works.  You may find that the INCLUDES module does not have a structure that you need.  You can then include it as above, add it to the INCLUDES module or make your module as described in the Modules chapter.   
  4983. Using Structures      
  4984. Now that the structure definitions are loaded we can make copies from the template.  To create one of these structures that you have defined, enter the name of the structure type followed by the name of the new copy. Enter:  
  4985. NewWindow MYNW 
  4986. MYNW .  ( print address of MYNW for fun ) 
  4987. For those familiar with 'C' the first line is equivalent to:  
  4988. STRUCT NewWindow MYNW; 
  4989. This creates a NewWindow structure that is used to describe how you want Intuition to open a new window.  To see how this member was defined and the names of its members enter:  
  4990. FILE? NEWWINDOW ( then hit 'y' when prompted ) 
  4991. If you want a window that is 300 pixels wide you need to set the WIDTH member of this structure.  JForth uses the naming conventions from the Assembler ".i" files so we refer to this member as NW_WIDTH. Enter:  
  4992. 300 MYNW S! NW_WIDTH 
  4993. The word S! looks up the offset for NW_WIDTH in the structure and adds it to the address on the stack.  It then looks up the size of the NW_WIDTH member and uses the equivalent of ! W! or C! to store the value to that address.  By using this syntax we are able to greatly optimize the referencing of structures.  (Hackers: Try using S! in a small colon definition then use DEF to examine the code.)  We can check that we set the value correctly by entering:  
  4994. MYNW S@ NW_WIDTH .  ( should print 300 ) 
  4995. The above two lines in 'C' would be:  
  4996. MYNW.width = 300; 
  4997. printf ("%d", MYNW.width); 
  4998. Note: In 'C' the case is critical so we cannot use upper case like we normally do for these examples.  For actual JForth code we normally use lower case too.   
  4999. Sometimes you may want to find the size of a structure so that you can allocate memory for it dynamically.  To find the size of a structure use the SIZEOF() word or use ALLOCSTRUCT.   
  5000. MEMF_CLEAR
  5001. SIZEOF() NEWWINDOW  ALLOCBLOCK  ( allocate structure )
  5002. Making an Array of Structures
  5003. Sometimes it is desirable to have an array of structures.  Suppose we want to create 10 gadgets.  We could define 10 of them with individual names but it might be more convenient to define an array of gadgets and address them by index.  The word ARRAYOF will do that for us.
  5004. 10 ARRAYOF GADGET  MY-GADGETS
  5005. 3 MY-GADGET . \ print address of gadget #3
  5006. Referencing Substructures      
  5007. Sometimes structures contain other structures as members.  To access the substructure you will need its address.  Once you have its address you can use S! and S@ as before.  You can find the address of any member of a structure by using the .. word.  An Intuition Screen, for example, contains its own RastPort.  Let us assume we have a variable called SCREEN-PTR that contains the relative address of a Screen.  To fetch the value of the foreground pen in its rastport we could use the following:  
  5008. SCREEN-PTR @  ( -- address-of-Screen ) 
  5009. .. SC_RASTPORT ( -- address-of-Screen's-RastPort ) 
  5010. S@ RP_FGPEN . ( print pen value ) 
  5011. In 'C' that would be:  
  5012. printf("%d", SCREEN_PTR->RastPort.FgPen); 
  5013. Often structures will contain pointers to other structures.  If it is an Amiga structure, then the pointer will be the absolute address of that other structure.  A Window, for example, contains a pointer to a RastPort. Assume we have a Window's relative address in the variable WINDOW-PTR. Let's fetch its RastPort's drawing mode.   
  5014. WINDOW-PTR @ ( -- address-of-Window ) 
  5015. S@ WD_RASTPORT ( fetch Rastport's Address
  5016. ( automatically convert to relative ) 
  5017. S@ RP_DRAWMODE 
  5018. Note that S@ and S! are intelligent about how they handle values.  If a structure member is defined as APTR, an address being stored into that member using S! will be converted to absolute using the equivalent of IF>ABS.
  5019. Accessing Array Members in Structures    
  5020. Some structures have members that are arrays of values.  A BitMap structure, for example, contains an array of pointers for up to 8 individual bit planes.  To reference these arrays, use .. to get the base address of the array, then add the offset required to get to the particular member of the array.  To do this you will need to know the width of the values in the array.  Suppose we want to fetch the address of the third bit plane in a BitMap called MYBM.  We could use the following:  
  5021. MYBM .. BM_PLANES  ( address of 0th bitplane ) 
  5022. 2 CELLS +  ( offset to 3rd bit plane ) @ 
  5023. Examining Structures with DST    
  5024. When you are working with structures, it is handy to be able to see all of the values in it at once.  JForth provides a tool that makes this easy. Enter:  
  5025. INCLUDE? DST JU:DUMP_STRUCT 
  5026. This is a handy debugging tool. Enter:
  5027. NEWWINDOW MYNW  ( unless already defined )
  5028. 120 MYNW S! NW_WIDTH
  5029. MYNW DST NEWWINDOW 
  5030. DST will use the structure template whose name follows to dump the contents of a structure whose address is on the stack.  The first column is the values of the members.  The middle column tells you the width of the member in bytes and whether it is Signed or Unsigned.  If a member is signed, then 16 and 8 bit members will be sign extended into a 32 bit number when placed on the stack.  Try putting the last line above in a word called DMYNW then experiment with setting members of MYNW then dumping them out.   
  5031. Defining Your Own Structures    
  5032. JForth provides tools for you to define your own structure.  The syntax is very similar to 'C'.  A possible 'C' structure and the corresponding JForth structure are shown below to give you an idea of how they relate.   
  5033. /* A 'C' structure. */ 
  5034. struct datrec   { 
  5035.     ushort howmany, *sval_ptr; 
  5036.     long   bigval; 
  5037.     struct list *alist; 
  5038.     struct rastport myrastport; 
  5039.     aptr   some_mem; 
  5040.     short  table[32]; 
  5041. }; 
  5042. In JForth, we should add a prefix to make the member names unique.  Let's use "DR_".  The same structure in JForth would be defined as:  
  5043. :STRUCT DATREC     ( Start defining a structure ) 
  5044.     USHORT DR_HOWMANY 
  5045.     APTR   DR_SVAL_PTR ( pointer to a SHORT ) 
  5046.     LONG   DR_BIGVAL 
  5047.     APTR   DR_ALIST        ( only a pointer ) 
  5048. ( member is a complete structure ) 
  5049.     STRUCT RASTPORT DR_MYRASTPORT 
  5050.     APTR   DR_SOMEMEM 
  5051.     32 2 * BYTES DR_TABLE    ( make room for array ) 
  5052. ;STRUCT     ( Terminate definition ) 
  5053. For more examples of how to define your own structures, look at the ".h" files in JI: and compare them to the 'C' includes.   
  5054. Structure Glossary      
  5055. The words to support the use of structures are in JU:C_STRUCT and JU:MEMBER.  They are loaded as part of the normal JForth image.   
  5056. Structure Accessing Words
  5057. By using S@ and S! instead of ..@ and ..!, you can almost completely ignore relative versus absolute addressing.  It will be taken care of for you automatically.
  5058. ..    ( struct-addr <member-name> -- member-addr )  
  5059. Calculate the address of a structure member by adding an offset to the base of the structure.   
  5060. ..@   ( struct-addr <member-name> -- value )  
  5061. Fetch the value stored in a structure member.  This will automatically use the appropriate @ word for that member.  Here is a table of the equivalent @ operator used for various member types:
  5062. BYTE uses C@
  5063. SHORT uses W@
  5064. LONG uses @
  5065. RPTR uses @
  5066. APTR uses @    ( see S@ )
  5067. The member must be either 1,2 or 4 bytes wide for this to work.  For members that are bigger than 4 bytes, eg. an array, use a combination of " .. " and the normal @ and ! words.  With this system, you no longer have to worry about the size of your member, just how you use it! If the member is defined as signed BYTE or SHORT then it will be sign extended to 32 bits.  This allows you to store negative numbers in 8 or 16 bit members.  See B->S in the main glossary for more information about sign extension.
  5068. ..!   ( value struct_addr <member-name> -- )  
  5069. Store value into structure member.  The word ! , W! , or C! will be used depending on the width of the member as in ..@.
  5070. S@  ( struct-addr <member-name> -- value )
  5071. .iS@ , definition,18-;Equivalent to ..@ except APTR members are converted to relative.  The following two lines are thus functionally equivalent:
  5072. MNW ..@ NW_Title  IF>REL
  5073. MNW S@ NW_Title
  5074. S!  ( value struct_addr <member-name> -- )
  5075. .iS! , definition,18-;Equivalent to ..! except APTR members are converted to absolute.  The following two lines are thus functionally equivalent:
  5076. 0" Plots" IF>ABS MNW ..! NW_Title
  5077. 0" Plots" MNW S@ NW_Title
  5078. SIGNED-MEMBERS  ( -- addr , variable to control compilation )  
  5079. If this flag is TRUE (the default) then when ..@  is compiled it will distinguish between SIGNED and UNSIGNED members.  Version 1.2 treated all members as UNSIGNED.  If you are having a compatibility problem with 1.2 involving structures, try setting this variable to FALSE and recompile your application.   
  5080. Structure Defining Words     
  5081. :STRUCT  ( <name> -- , Start defining a structure. )  
  5082. ;STRUCT  ( -- , Terminate a structure definition. )  
  5083. APTR  ( <name> -- , Amiga absolute pointer )
  5084. This member must be an absolute address when used by the Amiga.  If you use S@ and S!, then addresses will be automatically be converted between relative(JForth) and absolute(Amiga) as needed.
  5085. ARRAYOF   ( n <structure> <name>  -- )
  5086. Allocate an array in the dictionary with the given name that has room for N of the specified structures.  The name will take an index and return an address just like ARRAY.
  5087. 20 ARRAYOF  GADGET  MY-GADGETS
  5088. 3  MY-GADGET . \ print address of 3# gadget
  5089. ALLOCSTRUCT  ( <structure>  -- addr-structure | 0 )
  5090. Dynamically allocate a structure from memory.  This address must eventually be freed using FREEBLOCK.
  5091. BYTE     ( <name> -- , Define a SIGNED 8 bit member )  
  5092. You do not have to worry about word alignment of subsequent members.  SHORT and LONG will automatically place themselves at a word boundary after a BYTE member.  This is the way 'C' does it.  In assembly you have to put in dummy bytes sometimes to avoid address errors.   
  5093. BYTES    ( #bytes <name> -- , define multibyte member)  
  5094. This is used for defining the other member types.  LONG is defined as " 4 BYTES " .  Arrays can be put in a structure by multiplying the width of the array units by the number of units.  To make a structure member that is 10 LONG words, use:  
  5095. 10 4 * BYTES MY_LARRAY 
  5096. LONG     ( <name> -- , define a 32 bit  member )  
  5097. RPTR   ( <name> -- , define a relative pointer )
  5098. A pointer member that contains a JForth relative address.  This will bot be converted by S@ or S!.
  5099. SHORT    ( <name> -- , define a SIGNED 16 bit member )  
  5100. UBYTE    ( <name> -- , define an UNSIGNED 8 bit member )  
  5101. USHORT   ( <name> -- , define an UNSIGNED 16 bit member )  
  5102. STRUCT   ( <struct-type> <name> , structure as member )  
  5103. Define a structure member that is another type of structure.  JForth will look up how big that structure is and make room for the right number of bytes.   
  5104. Member UNIONs      
  5105. A 'C' structure sometimes has several members that occupy the same memory space.  These members are said to be part of a UNION.  These are useful when you want to use the same part of  a structure for different purposes. Let's suppose that you are passing a structure that contains a type field and then data that varies with the type.  With one type, you want to pass an X,Y pair as SHORT values.  With the other type you want to pass a single 32 bit address.  You could do this by creating a structure like the following:  
  5106. \ Create flexible structure.  
  5107. :STRUCT FLEXDAT 
  5108.     SHORT DATA_TYPE   \ 0 for X,Y, 1 for PTR
  5109.     UNION{           ( Start union ) 
  5110.        SHORT XPOS 
  5111.        SHORT YPOS 
  5112.     }UNION{ 
  5113. \ Has same offset as xpos, but is 32 bits wide.  
  5114.        APTR DATA_PTR 
  5115.     }UNION 
  5116.     LONG MORE_DATA 
  5117. ;STRUCT 
  5118.  
  5119. : REPORT.DATA  ( addr-flexdat -- , Report appropriate data. ) 
  5120.     DUP S@ DATA_TYPE 0 = ( check type ) 
  5121.     IF DUP S@ XPOS ." X = " .  
  5122.        DUP S@ YPOS ." , Y = " . cr 
  5123.     ELSE DUP S@ DATA_PTR    ( get pointer to data ) 
  5124.          @ ( get actual data ) ." Data = " . cr 
  5125.     THEN 
  5126.     S@ MORE_DATA ." more data = " . cr 
  5127. FLEXDAT FD-1 
  5128. HEX 01230092 FD-1 ..! DATA_PTR 
  5129. 0 FD-1 ..! DATA_TYPE 
  5130. REPORT.DATA 
  5131. 1 FD-1 ..! DATA_TYPE 
  5132. REPORT.DATA 
  5133.  
  5134. In the preceding example, XPOS and YPOS occupy the same position in the structure as DATA_PTR does.  If the parts of a union are not the same size, then the size of the largest part will be used.  Subsequently defined members will be after that largest part.  The following words must always be used in the given order:  
  5135. UNION{   ( -- old-offset new-offset )
  5136. Start first half of a union.  
  5137. }UNION{  ( old-offset new-offset -- old-offset max-offset ) 
  5138. Mark next part of union.  Reset offset in structure so that subsequently defined members will overlap previously defined members.   
  5139. }UNION   ( offset2 -- )
  5140. Terminates union.  
  5141. You don't have to worry about these offsets.  They are used for communication between the UNION words and can be ignored.  Just be careful that you don't put other stuff on the stack that might interfere with these.   
  5142. Addressing Considerations - Important!!!    
  5143. JForth uses addresses that are relative to the base of the JForth kernel.  This greatly simplifies the usage of JForth because dictionary addresses don't change between successive runs for JForth.  One advantage is that you can store JForth dictionary addresses in variables, do a SAVE-FORTH, rerun your code and those addresses are still valid. 
  5144. The Amiga, however, must use absolute addresses to perform its work.  This implies that you may only pass absolute addresses to its library routines.  You must also use absolute addresses when setting a pointer in a structure that the Amiga will use.  Word like CALL>ABS ,  S@ and S! help keep track of when these conversions are needed and do them for you.  It is rare, therefore, to have to worry about this issue.  It is important, however, to understand it so that you can handle unusual situations.
  5145. Suppose that you want to place a pointer to a null terminated string inside a NewWindow structure (which, of course, is being prepared for AmigaDOS to process).  The word 0" will return a relative address.  You must convert this to absolute by using >ABS before placing it in the structure.   (S! automatically converts the relative address to absolute; if we use ..! to write the value, we will have to manually convert it using >ABS).
  5146. Some Amiga routines use the NULL value for an address to indicate an error, or a special condition.  If you use >ABS or >REL on a NULL it is no longer NULL .  For these cases you should use IF>REL and IF>ABS to preserve NULL .  These are simply defined as:  
  5147. : IF>REL  DUP IF >REL THEN ;  
  5148. Here is an example of using >ABS and IF>REL  
  5149. INCLUDE? NEWWINDOW.SETUP JU:AMIGA_GRAPH 
  5150. \ Make an instance of a NewWindow structure.  
  5151. NEWWINDOW IDEALWINDOW 
  5152. IDEALWINDOW NEWWINDOW.SETUP  ( Set default values ) 
  5153.  
  5154. : NAME&OPEN ( -- window , Name the window and open it. ) 
  5155.     0" WORK WINDOW"  >ABS   ( convert address ) 
  5156.     IDEALWINDOW ..! NW_TITLE  ( store in structure ) 
  5157.     IDEALWINDOW >ABS    ( Convert for Amiga call ) 
  5158.     CALL INTUITION_LIB OPENWINDOW 
  5159. \ Convert absolute window address to relative for JForth.  
  5160.     IF>REL  ( preserve NULL )    ;
  5161.  
  5162. : CHECK.WINDOW ( window -- , Check window pointer <> NULL ) 
  5163.     NOT IF ." Window not opened!!" ABORT THEN   ;
  5164.  
  5165. NAME&OPEN           \ Get relative address of open window
  5166. DUP CHECK.WINDOW 
  5167.   ..@ WD_RPORT      \ Fetch absolute address of RastPort
  5168.   IF>REL            \ convert to relative
  5169.   ..@ rp_FgPen .    \ print pen color
  5170. The absolute address of the RastPort can be passed directly to Amiga graphics routines.  If you want to access members of this structure using JForth, you must first convert its address to relative.
  5171. Note that in the above example we could have almost entirely avoided having to consider absolute versus relative by using S! and CALL>ABS.  I say "almost" because we would still have to convert any address returned by the Amiga using IF>REL just like at the end of NAME&OPEN.
  5172. As a general guideline, when passing addresses between JForth words, pass RELATIVE addresses.  Do any required conversion to or from absolute, inside your words, before interfacing with the Amiga.   
  5173. H2J - Convert "xx.h" to "xx.j"
  5174. H2J is handy if you want to interface to an Amiga Library that has an associated ".h" file.  An example might be the A-Squared Live library or the ARP library.  The ".h" file will contain the definitions of constants and structures to be used with the Library.  To use the Library from JForth you will need a ".j" file containing JForth style structure and constant definitions.   
  5175. When we developed JForth 1.2, we needed something that would convert the Amiga include files. Thus H2J was born.
  5176. You can either use the Cloned version of H2J or compile it and use it directly from JForth.  To compile H2J, enter:  
  5177. INCLUDE JA:H2J.f
  5178. This will load ODE and whatever else it needs.   
  5179. H2J takes two filenames, an input and an output filename.  You may use full pathnames.   
  5180. H2J infile outfile 
  5181. To convert newlib.h to JForth style, enter:  
  5182. H2J newlib.h newlib.j 
  5183. H2J will prompt you at various times for one of two things. When it encounters a new structure definition, it will ask you to enter a prefix to add to the member names to make them unique.  Like Assembly, Forth requires you to use unique names for the structure members.  For a Window structure, for example, we use "wd_".  If the structure members already has a prefix, just hit return.   
  5184. H2J will also ask you to verify it's conversion if it encounters an unusually tricky line.  It is usually correct so unless you know it is wrong, just hit return.  If it is wrong, type in the line the way it should be.   
  5185. Don't panic if some little thing goes wrong.  You can always go back and edit the file.  We find that H2J will convert about 80% of the files completely.  The other 20% will require minor tweaking.
  5186.  
  5187. 18 -      Amiga Libraries and Structures
  5188.  
  5189.     Amiga Libraries and Structures    18 -  
  5190.  
  5191.  
  5192.  
  5193.  
  5194.  
  5195.  
  5196. Chapter 19
  5197. Graphics Toolkit
  5198. Overview
  5199. These words were designed to give a simple starting point for interfacing to the Amiga graphics library.  The words are fairly generic.  An application written using them can (and has been) ported to or from other machines with different graphics environments.   
  5200. If need be, you can also access any of the advanced features of the Amiga by using the CALL and :STRUCT facilities.  So while these GR words do not access all of the Amiga facilities, you are not restricted from doing so. By looking at the source code, you will see how to extend this toolkit.   You should also look at the Chapter on miscellaneous Amiga tools for more graphics words.  For information on using the Amiga libraries, please refer to the Amiga ROM Kernel Reference Manual.
  5201. The majority of the demos in the JD: directory use this GR system so please refer to them for more examples of its use.
  5202. Graphics Tutorial
  5203. These words are designed to work with the concept of a current rastport. All drawing commands will act on that rastport.  To distinguish these words from other Forth words all of these routines will be prefaced with a 'GR' for GRaphics.   
  5204. To demonstrate how this system works, let's open a window and do some drawing.  The graphics subsystem is not normally loaded in the JForth dictionary.  To load this code, enter:  
  5205. INCLUDE? GR.INIT JU:AMIGA_GRAPH 
  5206. The above will load the graphics code from the file AMIGA_GRAPH only if GR.INIT has not already been defined.  Before any use is made of the graphics system, we should make sure the graphics system is initialized properly.  To do this enter:  
  5207. GR.INIT 
  5208. This sets all of the variables to their proper state and opens the Graphics and Intuition libraries.  Now we need to load the information needed to talk to the Amiga libraries.  This normally resides in the ".J" include files.  These files contain the definitions of structures and constants.  Structures are simply a collection of variable organized in a specific way.  This organization is defined in the include files.  JForth provides the most commonly needed information in precompiled modules.  To load the main module, enter:
  5209. GETMODULE INCLUDES    ( link in precompiled includes )
  5210. Now we should open a window for drawing.  First we need to declare a NewWindow structure.  This is a template that gives Intuition some information about the window we desire including its width, height, location, input event flags, etc.  This structure will occupy some memory space in the JForth dictionary.  We refer to structures by the address of their first byte.  Every byte in the computer has an address which is simply a number which uniquely identifies it.  When we say the we are "passing a structure" or "passing a pointer to a structure" we mean that we are passing the address of the structure.  (Pointer means address.)
  5211.  JForth provides a word called NEWWINDOW.SETUP  that will set the values in a NewWindow structure to some reasonable values. 
  5212. NEWWINDOW MY-WINDOW       ( define a structure ) 
  5213. MY-WINDOW NEWWINDOW.SETUP ( set default values in structure)
  5214. We can use FILE? to see how the NewWindow structure is defined. Enter:
  5215. FILE?  NEWWINDOW
  5216. and hit 'Y' when asked if you want to see the source code.  Let's examine and change some of the default settings.  Enter:
  5217. NEWWINDOW .  ( print address of first byte just for fun )
  5218. NEWWINDOW S@ NW_WIDTH .  ( set by NEWWINDOW.SETUP )
  5219. 500 NEWWINDOW S! NW_WIDTH  ( let's change it to 500 )
  5220. NEWWINDOW S@ NW_WIDTH .  ( did it work )
  5221. The 500 in the above example was the width of the window in pixels or video dots.  We can now pass that structure to the Amiga Intuition Library asking for a window.   
  5222. MY-WINDOW GR.OPENCURW  .  ( open the window )
  5223. Notice that a window has been opened.  You may also have noticed that a value was left on the stack  That was the window pointer.   You should always check to make sure that this pointer is non-zero.  If it is zero, it means that the window did not open and your program will probably crash if you pretend that it did.
  5224. To draw in this window we can set the current color, and then issue move and draw commands.  These commands are based on using an imaginary color pen.  To pick up the pen and reposition it you use GR.MOVE .  To put the pen down and drag it in a straight line you use GR.DRAW .   
  5225. 2 GR.COLOR! 
  5226. 30 30 GR.MOVE 
  5227. 200 55 GR.DRAW   ( draw a line from  30,30 to 200,55 ) 
  5228. 300 100 GR.DRAW  ( draw a line from 200,55 to 300,100 )
  5229.  
  5230. Now let's try drawing a filled rectangle in another color.   
  5231. 1 GR.COLOR! 
  5232. 20 20 100 120 GR.RECT   ( draw filled rectangle )
  5233.  
  5234. We can also output a text message, try entering:  
  5235. 3 GR.COLOR! 
  5236. 250 60 " Hello!" GR.XYTEXT 
  5237. The Amiga uses numbers to reference different colors.  The Amiga video circuitry displays a picture by reading these numbers from memory and converting them to an actual color.  It uses a color table, or pallette, to figure out what color should be displayed for a given number.  These colors can be changed using the Preferences program described in your Amiga user manual.   
  5238. To finish this session we should close the window and terminate the graphics system.   
  5239. GR.CLOSECURW 
  5240. GR.TERM 
  5241. A Simple Graphics Program    
  5242. Let's experiment with defining a Forth word that draws random vectors. (Vector is the graphics industry word for a single line segment.) We can use the Forth word CHOOSE which selects a random value between 0 and whatever value is on the stack.  You may want to enter these in a file so that you can modify the program when done.   
  5243. \ Load necessary code.  
  5244. INCLUDE? GR.INIT JU:AMIGA_GRAPH 
  5245. INCLUDE? ?CLOSEBOX JU:AMIGA_EVENTS 
  5246. INCLUDE? CHOOSE JU:RANDOM 
  5247.  
  5248. ANEW TASK-RANDOM_LINES
  5249.  
  5250. NEWWINDOW  MYNW
  5251. : DRAW.RAND  ( -- , draw a random vector ) 
  5252.     300 CHOOSE   ( generate random X ) 
  5253.     120 CHOOSE   ( generate random Y ) 
  5254.     GR.DRAW      ( draw line ) 
  5255.  
  5256. : MANY.RAND ( -- , draw many random vectors ) 
  5257.     GR.INIT
  5258.     MYNW NEWWINDOW.SETUP
  5259.     MYNW  GR.OPENCURW 
  5260.     IF  ( Check to make sure window opened !!!!)
  5261.         BEGIN
  5262.             DRAW.RAND 
  5263.             ?CLOSEBOX   ( has closebox been hit ) 
  5264.         UNTIL 
  5265.         GR.CLOSECURW
  5266.     THEN
  5267.     GR.TERM 
  5268.  ?CLOSEBOX will return a TRUE if the closebox is ever hit.  This gives you a way out of the program. 
  5269. The word GR.OPENTEST gives you an easy way to open a window for testing.  It will automatically ABORT if the window did not open.
  5270. Extending the Graphics Toolbox    
  5271. You may want to add new words that act on the "current RastPort".  If so, just remember that the RastPort is stored in ABSOLUTE mode to save us having to convert it before calling the Amiga Libraries.  Here is an example of a new routine to draw a single pixel in the current RastPort.   
  5272. : GR.POINT  ( x y -- , draw single point ) 
  5273.     GR-CURRPORT @ -ROT  ( -- rp x y ) 
  5274.     CALLVOID GRAPHICS_LIB WritePixel 
  5275. Generic Graphics Glossary     
  5276. There are three main types of routines in this toolkit.  The Control Routines initialize and terminate data structures, and are involved with opening and closing windows.  The Output Primitives produce actual graphics output in the current rastport.  The Output Attribute involve the appearance, colors, modes, etc.  of the Output Primitives.   
  5277. Control Routines      
  5278. GR.INIT ( -- , Initialize the Graphics Subsystem )  
  5279. Set attributes to their default values.  It also opens the Graphics and Intuition libraries.  This word MUST be called before using any of the other words.  Calling this routine twice will NOT result in an error.   
  5280. GR.TERM ( -- , Terminate the Graphics Subsystem )  
  5281.  
  5282. These words are Amiga specific words for setting up NewWindow structures and opening windows.   
  5283. GR.CLOSECURW ( -- , Close CURRENT window if open)
  5284. This command looks in the variable GR-CURWINDOW for a window pointer and closes it if one is there.  It then clears GR-CURWINDOW and GR-CURRPORT.
  5285. GR.CLOSEWINDOW ( Window -- , Close an Intuition Window )
  5286. If this window is the same as the window stored in the variable GR-CURWINDOW then both GR-CURRPORT and GR-CURWINDOW will be cleared.  This is to prevent a window from being closed twice, a fatal error, when working with multiple open windows.
  5287. GR-CURWINDOW  ( -- addr , Variable with rel addr of Window)  
  5288. GR-CURRPORT   ( -- addr , Variable with abs addr of RastPort)  
  5289. This variable contains the ABSOLUTE address of the Rastport.  This is used instead of the relative address because most of the Amiga graphics routines require an absolute rastport address.  See >REL.   
  5290. GR.OPENCURW ( NewWindow -- Window | 0 )
  5291. Open a window based on the requested values set in the NewWindow structure.  Returns the relative address of a window structure or 0 if it could not open.  Be sure to check this return value.  If a window does open, this word calls GR.SET.CURWINDOW to make this the current window for drawing.
  5292. GR.OPENTEST ( -- , Open a window for experimentation. )  
  5293. This opens a window for testing.  It can be used in place of the code in the first example.  It uses a NEWWINDOW structure called WINDOWTEMPLATE . This structure can be reused by other programs.   
  5294. GR.SET.CURWINDOW  ( Window -- , Sets the current Window )  
  5295. This sets the current Rastport to this windows Rastport.  Subsequent drawing operations, therefore, will take place in this window.   If you are using multiple windows, you should save your own window pointers to each of them.  You can call this word to determine which of your windows will be drawn into by the GR.xxx routines. 
  5296. The variables GR-CURRPORT and GR-CURWINDOW are set by this routine.
  5297. NEWWINDOW   ( <name> --INPUT-- , define a NewWindow structure )  
  5298. NEWWINDOW.SETUP  ( newwindow -- , set defaults for a new window )  
  5299. This loads a request structure for a 640 by 200 window that will open in the Workbench screen.  It will have a Close gadget and a Sizing gadget. You can modify any of these defaults before calling GR.OPENWINDOW to get different kinds of windows. 
  5300.  
  5301. Output Primitives      
  5302. GR.CLEAR ( -- , Clear the current drawing surface. ) 
  5303. The rectangle will be based on the current windows drawing surface. 
  5304. GR.DEHIGHLIGHT ( x1 y1 x2 y2 -- , DEHighlight a Rect Region)  
  5305. Reverse the effect of GR.HIGHLIGHT  
  5306. GR.DRAW ( xpix ypix -- , Draw a line. )  
  5307. This will draw a line from the current position to xpix, ypix using the current attributes.   
  5308. GR.FONT! ( font -- , calls SetFont() for current RastPort ) 
  5309. See the file JD:DEMO_FONTS for an example. 
  5310. GR.FONT@ ( -- font , get font from current RastPort ) 
  5311. GR.HIGHLIGHT ( x1 y1 x2 y2 -- , Highlight a Rectangular Region)  
  5312. This will highlight a region to bring attention to it.  On the Amiga this will be done by XORing with color = 3.   
  5313. GR.MOVE ( xpix ypix -- , Move the current position to xpix, ypix)  
  5314. GR.NUMBER ( n -- , Display number at current position. )  
  5315. If you need special formatting, you can format the number separately and draw using GR.TYPE .   
  5316. GR.RECT ( x1 y1 x2 y2 -- , Draw a rectangle )  
  5317. This will draw a rectangle using the current color.  The current position will be left at x1, y1.
  5318. Warning!  Make sure that X2 >= X1 and that Y2 >= Y1.  Otherwise the Amiga library routine will overwrite a huge part of chip memory and you will crash.  See JD:DEMO_BOXES.
  5319. GR.TEXT ( $string -- , Draw a text string )  
  5320. Draw text at the current position.  The string must have a byte count at the given address.  The current position will be left at the end of the text.   
  5321. " Hello" GR.TEXT
  5322. GR.TEXTLEN  ( addr count -- xpixels , x size of string ) 
  5323. Returns length of string in pixels if drawn in current font. This can be used to right justify text by moving XPIXELS to the left of your right margin and drawing from there. 
  5324. 100 \ right margin
  5325. " Hello" COUNT GR.TEXTLEN -  \ calc x position
  5326. 50 ( -- x y ) GR.MOVE  \ to start
  5327. " Hello" GR.TEXT  \ will end at x=100
  5328. GR.TYPE ( addr count -- , Draw text, like Forth TYPE)  
  5329. GR.XYTEXT ( xpix ypix string -- , Draw a text string )  
  5330. Draw text at the given position.  This is essentially GR.TEXT that does a move first.   
  5331.  
  5332. Output Attributes      
  5333. The appearance of these output primitives can be controlled by the setting of output attributes.  These attributes remain in effect until changed. The setting words are balanced by query words so that an environment can be saved, changed, and then restored by low level code.  The setting words end in ! and the query words end in @ .   
  5334. GR.COLOR! ( color-index -- , Set the color for drawing.) 
  5335. A color-index is a number that references a color defined in the current pallette.  See JD:DEMO_RGB for an instructive example.
  5336. 3 GR.COLOR! 
  5337. GR.BCOLOR! ( color-index -- , Set the background color.)  
  5338. The background color is used when clearing the screen and for filling in around text.   
  5339. GR.MODE! ( mode -- , Set the drawing mode.)  
  5340. This controls the logic mode that is used to modify the pixels when drawing.  You can use the Amiga constants JAM1 , JAM2 , and COMPLEMENT.  We have also defined two constants GR_INSERT_MODE and GR_XOR_MODE to promote portability.  There is an official bug in the Amiga Library that forces the color to index 3 when in COMPLEMENT mode.   
  5341. GR.COLOR@ ( -- color-index , Fetch the color for drawing.)  
  5342. GR.BCOLOR@ ( -- color-index , Fetch the background color.)  
  5343. GR.MODE@ ( -- mode , Fetch the drawing mode.)  
  5344.  
  5345. Graphics Input      
  5346. In event driven systems, all input events should be routed through a top level routine that can handle any event that is generated.  These include mouse movement, button presses, menu picks, window close box hits, etc. The type of events generated and the way that they are handled is different in every application.  For this reason, we have not included a routine that only handles mouse location input.  For information on how to access input events, see the documentation on the EV routines for event processing.  You can also examine the DEMO_PAINT file for an example of graphics input.
  5347. Event Driven Programming.     
  5348. A new style of programming is evolving to meet the needs of highly interactive systems.  In modern user interfaces, the user is normally free to use any input that the program offers.  These might include picking from menus, moving windows around, entering graphic information, hitting the keyboard, or poking at other gadgets on the screen.  The program must be ready to respond to any of these input events.  A typical program is structured with a loop at the top of the program that gets input events and processes them with a case statement.  The loop is exited when, for example, a CLOSEBOX is hit, or QUIT is selected from a menu.  Since the user's input events control the flow of the program, this style is referred to as 'Event Driven Programming'.   
  5349. The Amiga provides support for this style of programming.  When a window is opened, the programmer can select which types of events can be generated by setting the IDCMP flags.  Messages can then be received from that window that contain one of the selected events or a NULL event if nothing happened.  Please refer to the Intuition manual, Chapter 8, that discusses IDCMP and IntuiMessages for details.   
  5350. Please also examine the files JD:DEMO_MENUS and JD:DEMO_PAINT for examples of how to use this system.   
  5351. Routines in JU:AMIGA_EVENTS - EV.xxxx
  5352. This part of the system normally has to be developed from scratch to meet the needs of individual programs.  We have included some simple routines, however, to get people started.   
  5353. ?CLOSEBOX ( -- flag )
  5354. Checks for a CLOSEBOX hit in GR-CURWINDOW.  This is handy if the only kinds of events you want are CLOSEBOX events. All other classes of events are lost.  Used in the demos.   
  5355. EV.2CLICK?  ( -- flag )
  5356. Returns TRUE if last mouse click was the second click of a double click.  See JD:DEMO_CLICK
  5357. EV.FLUSH  ( -- , flush all events from queue )  
  5358. This does EV.GETCLASS with GR-CURWINDOW until a NULL event is received.  
  5359. EV.GETCLASS ( window -- class , get message class or NULL )  
  5360. This word calls GET.PORT.MSG on the USERPORT associated with the window. If an input event has occurred, the relevant information is extracted and placed in variables for easy access.  See PARSE.PORT.MSG below.  The message is then replied to using ReplyMsg.   
  5361. EV.GETXY ( -- x y , get last reported mouse position )  
  5362. This just fetches the values in EV-LAST-MOUSEX and EV-LAST-MOUSEY .   
  5363. EV.GETXY00 ( -- x y , gets x,y corrected for GIMMEZEROZERO )  
  5364. This can be used if you are getting x,y from a GIMMEZEROZERO window.  It corrects for the border of the window.   
  5365. EV.WAIT  ( window -- , wait for message, leave in queue )
  5366. If you are just waiting for an event, you should call this instead of sitting in a polling loop.  Otherwise you will eat up all the CPU time and leave very little for other tasks.  When it returns, you can call EV.GETCLASS.
  5367. GET.PORT.MSG  ( port -- class | 0 )
  5368. This is called by EV.GETCLASS.
  5369. PARSE.PORT.MSG  ( message -- , extract info, place in variables)
  5370. The variables are as follows: 
  5371. EV-LAST-CODE
  5372. EV-LAST-IADDRESS
  5373. EV-LAST-MOUSEX     EV-LAST-MOUSEY
  5374. EV-LAST-MICROS     EV-PREV-MICROS 
  5375.  
  5376. This code is in the file JU:AMIGA_EVENTS.
  5377.  
  5378. 19 -      Graphics Toolkit
  5379.  
  5380.     Graphics Toolkit    19 -  
  5381.  
  5382.  
  5383.  
  5384.  
  5385.  
  5386.  
  5387. Chapter 20
  5388. EZMenu System      
  5389. Tutorial
  5390. The Amiga provides a very sophisticated pull down menu system that greatly enhances the usability of an application.  A group of menus can be linked together and associated with a specific window.  Each menu has a list of items that the user can select.  Each item can be either text or a bitmapped image.  Menu picks are obtained by requesting IDCMP messages. When an application receives a menu pick, it executes the appropriate piece of code.  A detailed explanation of how this system works can be found in the Intuition Manual.   
  5391. Using JForth, you can access all of the features of Intuition Menus. Because the Amiga has so many options, however, this can be a somewhat difficult process.  We decided to offer a simplified Menu interface that will suffice for most applications.  We assume that you would like one or more menus with simple text items.  The EZMENU system will build Menu, MenuItem, and IntuiText structures based on this assumption.  If you want more fancy menus, you can still use the EZMENU system, but you will need to tweak things a bit.   
  5392. An example of using the EZMenu system can be found in the file JD:DEMO_MENUS.
  5393. EZMenu Structure
  5394. The EZMenu system is based on the use of a special JForth  structure called an "EZMenu".  The EZMenu contains an Intuition Menu structure, a pointer to an array of IntuiText items, a pointer to an array of CFAs (function addresses), and a count of how many items are in the EZMenu.  It is defined in the file JU:AMIGA_MENUS .  To use the EZMenu system, you first create a number of EZMenu structures.  The address of these structures is then passed to the EZMenu routines.  By combining the EZMenu routines with the low level Menu routines described later, you can have total control over the menus.   
  5395. AMENU Program
  5396. Let's write a simple menu program that opens a window and attaches to it one menu with three items.  We will then scan for Amiga events and process any MENUPICK events.  Once you are comfortable with the essentials covered by this program you can explore JD:DEMO_MENUS and JA:EZWALKER.F for more extensive examples.   
  5397. First we will need to compile the graphics and event support which we studied earlier and the EZMenu code.  I recommend typing this program into a file as we go since it is a little long for keyboard entry.   
  5398. INCLUDE? NEWWINDOW.SETUP JU:AMIGA_GRAPH 
  5399. INCLUDE? EV.GETCLASS     JU:AMIGA_EVENTS 
  5400. INCLUDE? EZMENU JU:AMIGA_MENUS 
  5401. In the file, after the INCLUDE?s, let's put a call to ANEW.  This will help us when we reload this program by automatically forgetting the previous version.  We will then create our own EZMenu structure to use with the EZMenu routines.  You will need one EZMenu structure for each menu.   
  5402. ANEW TASK-AMENU 
  5403. EZMENU MY-MENU 
  5404. Now let's write a word that will initialize our menu.  We need to allocate room for 3 menu items.  EZMENU.ALLOC? will allocate all the needed MenuItem and IntuiText structures needed for the menu.  EZMENU.SETUP will link all of these structures together and give the menu a name.  The 0 indicates that this is the 0th menu for the menu.  Menus and menu items are all numbered starting with zero.  We then use EZMENU.TEXT! to give each menu item a name Finally we assign a Command Sequence Key to the "Quit" item. This will allow us to quit by simply holding down the Right Amiga Key and hitting 'Q'.   
  5405. : MY-MENU.INIT  ( -- error? , INITIALIZE MENU ) 
  5406. \ Allocate space for 3 menu items 
  5407.     3 MY-MENU EZMENU.ALLOC?  \ returns 0 if it fails
  5408.     IF
  5409. \ Set name of menu and position in list.  
  5410.         0" Project" 0 MY-MENU EZMENU.SETUP 
  5411. \ Define the text for each menu item.  
  5412.         0" Open" 0 MY-MENU EZMENU.TEXT! 
  5413.         0" Close" 1 MY-MENU EZMENU.TEXT! 
  5414.         0" Quit"  2 MY-MENU EZMENU.TEXT! 
  5415.         ASCII Q 2 MY-MENU EZMENU.COMMSEQ!
  5416.         FALSE \ flag for NO error
  5417.     ELSE
  5418.         ." MY-MENU.INIT - Insufficient Memory!" CR
  5419.         TRUE  \ error flag
  5420.     THEN
  5421. This is all that is required to define the appearance of a menu.  If you want to get fancy you could modify some of the menu items to add checkmarks, graphic images, subitems, etc.  See EZMENU.ITEM[] for details on how to access individual items.   
  5422. We now need a word that will process a Menu Pick when it occurs.  The Amiga will generate a "menucode" that indicates which item was picked.  By using ITEMNUM() , MENUNUM() , and SUBNUM() you can determine exactly which item or subitem in any menu was picked.  We only have one menu and no subitems so we only need ITEMNUM().   
  5423. Let's keep a flag variable that will tell us when to stop.  If we hit "Quit" from the menu we can just turn that variable on.  If we hit the other two items, just output a message.  Nothing fancy.  That's for you to add!  
  5424. VARIABLE QUIT-NOW    ( time to stop? ) 
  5425. : DO.WHATEVER ( menucode -- , act on menu item chosen ) 
  5426.     DUP MENUNULL = 
  5427.     IF DROP   ( not a complete menu pick ) 
  5428.     ELSE ( -- menucode ) 
  5429.         ITEMNUM()  ( -- item# ) 
  5430.         CASE 
  5431.             0 OF ." Open File!" CR ENDOF 
  5432.             1 OF ." Close File!" CR ENDOF 
  5433.             2 OF ." Quit!" CR QUIT-NOW ON ENDOF 
  5434.         ENDCASE 
  5435.     THEN 
  5436. The program will probably be receiving more than just Menu Picks.  There will be Mouse Clicks, CloseWIndow events, etc.  We need to treat the differently.  This next word passes Menu Picks to DO.WHATEVER and also turns on the quit flag if the CloseWindow Gadget is hit.  The information on what menu item was picked is stored in EV-LAST-CODE by the EV.GETCLASS word.  This word is described in the section on Event Handling.   
  5437. \ Process IDCMP events.  
  5438. : HANDLE.EVENT ( eventclass -- ) 
  5439.     CASE 
  5440. \ Perform Menu actions 
  5441.         MENUPICK 
  5442.         OF  EV-LAST-CODE @ DO.WHATEVER 
  5443.         ENDOF 
  5444. \ Set quit flag if CLOSEBOX hit.  
  5445.         CLOSEWINDOW 
  5446.         OF QUIT-NOW ON 
  5447.         ENDOF 
  5448.     ENDCASE 
  5449. This last word only handles one event.  We, therefore, need a loop that will scan for events in our application window and pass them to HANDLE.EVENT for processing.  We use GR-CURWINDOW, which holds a pointer to the current window, to get events from.  The loop will quit when the QUIT-NOW flag is turned on.   
  5450. : LOOP.MENU ( -- , poll for events ) 
  5451.     QUIT-NOW OFF 
  5452.     BEGIN 
  5453. \ wait for an event so we don't tie up the Amiga
  5454.         GR-CURWINDOW @ EV.WAIT
  5455. \ Check for events in the current window.  
  5456.         GR-CURWINDOW @ EV.GETCLASS ?DUP 
  5457.         IF HANDLE.EVENT 
  5458.         THEN 
  5459.         QUIT-NOW @ 
  5460.     UNTIL 
  5461. Now we just need to tie all this together.  We start by initializing graphics and opening a window.   I then initialize the menu and attach it to our window using SetMenuStrip().  When I terminate I detach the menu with ClearMenuStrip() and also free the memory declared by EZMENU.ALLOC.  I then run the whole thing from the AMENU word.  I have found that this style of organizing a program, with a clear INIT and TERM helps reduce bugs and makes for more readable code.   Note how the error codes from GR.OPENCURW and MY-MENU.INIT propagate up to the highest level.
  5462.     NEWWINDOW  MYNW
  5463. : AMENU.INIT ( -- error? , set everything up ) 
  5464.     TRUE \ set default error return
  5465.     GR.INIT
  5466.     MYNW NEWWINDOW.SETUP
  5467.     MYNW GR.OPENCURW  \ returns &window if successful
  5468.     IF
  5469. \ Initialize menu and attach to window.  
  5470.         MY-MENU.INIT 0=
  5471.         IF
  5472.             GR-CURWINDOW @ MY-MENU SETMENUSTRIP()
  5473.             DROP FALSE  \ replace TRUE since no error
  5474.         THEN
  5475.     THEN
  5476. : AMENU.TERM ( -- , clean up menus and close window. ) 
  5477.     GR-CURWINDOW @ ?DUP
  5478.     IF
  5479.         CLEARMENUSTRIP()
  5480.     THEN
  5481.     MY-MENU EZMENU.FREE 
  5482.     GR.CLOSECURW
  5483.     GR.TERM
  5484. : AMENU ( -- , do it all) 
  5485.     AMENU.INIT 0=  \ Everything OK?
  5486.     IF
  5487.         LOOP.MENU
  5488.     THEN
  5489.     AMENU.TERM 
  5490. cr ." Enter:    AMENU    to see demo." cr 
  5491. I like to close my program files with a reminder of what to enter to run the program.   
  5492. EZMenu Glossary      
  5493. For the following words, the parameter 'ezmenu' refers to the address of an EZMenu structure.  All of the addresses passed to and received from these routines are JForth relative addresses unless otherwise specified.  All numbering is zero based.  The first MenuItem, therefore, has an item# of 0.  For the following examples, assume that you have created two menus, as follows:  
  5494. EZMENU MAINMENU 
  5495. EZMENU EDITMENU 
  5496. EZMENU   ( <name> --input-- , Create an EZMenu structure. )  
  5497. EZMENU.ALLOC? ( #items ezmenu -- &items | 0 )
  5498. Allocate memory needed for the MenuItems, the Intuitext items, and the CFA array.  The first MenuItem is then linked to the Menu.  If any of the allocations fail, a zero is returned.  Otherwise the address of the items is returned.  You should check the return value before proceeding with any other EZMENU calls.
  5499. \ Allocate space for 6 menu items.  
  5500. 6 MAINMENU EZMENU.ALLOC?  .
  5501. EZMENU.CFA[]  ( item# &ezmenu -- &cfa, Address of cfa)
  5502. The EZMenu system maintains an array of CFAs associated with each menu.  A CFA is Forths equivalent to 'C's pointer to a function.  The array is initially filled with the  CFA of NOOP.  You can use EZMENU.EXEC to execute the appropriate word after a menupick.  The CFA of a word can be obtained by "ticking" a word with the word ' .  Any word's CFA can be placed in this array as long as it doesn't take from or leave anything on the stack.   
  5503. \ Set the CFA for menu item 3 
  5504. : ACT3 ( -- , No parameters allowed.) 
  5505.     ." Action 3" CR 
  5506.  ' ACT3  3 EZMENU.CFA[]  ( get address )  ! ( store ) 
  5507. EZMENU.COMMSEQ!  ( char item# &ezmenu -- , Set command key. )  
  5508. You can specify that a menu item be 'picked' by hitting the right Amiga key and a special character together.  This provides a handy shortcut to a menu action.   
  5509. \ Set Command Sequence key to 'W'.  
  5510. ASCII W  3 MAINMENU EZMENU.COMMSEQ! 
  5511. EZMENU.EXCLUDE!   ( mask item# &ezmenu -- , set auto-exclusion)  
  5512. Selecting one MenuItem can automatically cause others to become unchecked. See the Intuition Manual, page 6-6, for details.  Note that this word also sets the CHECKIT flag.   
  5513. EZMENU.EXEC   ( menucode menustrip -- , run menuitem's action)  
  5514. The MENUCODE is obtained from Intuition.  It is placed in the JForth variable EV-LAST-CODE by a call to EV.GETCLASS .  The menustrip is the same as the address of the first EZMenu in the list.   
  5515. EZMENU.FREE ( &ezmenu -- , Free memory from EZMENU.ALLOC)  
  5516. EZMENU.ITEM[]  ( item# &ezmenu -- &item , item address )  
  5517. If you want to modify a MenuItem structure for special handling, use this word to obtain it's address.   
  5518. EZMENU.TEXT[]  ( item# &ezmenu -- &intuitext , text address )  
  5519. If you want to modify a MenuItem's associated IntuiText structure, use this word to obtain it's address.   
  5520. EZMENU.TEXT!  ( text0 item# &ezmenu -- , Set text for MenuItem )  
  5521. The text must be a NUL terminated string such as that created by 0" . (That character in front of the quote is a zero.  In some fonts this is not obvious.)  
  5522. \ Set menu item text.  
  5523. 0" Write"  3  MAINMENU  EZMENU.TEXT! 
  5524. EZMENU.SET.FLAG  ( flag item# &ezmenu -- , OR flag with existing)  
  5525. You can set your own bits in the flags member of a MenuItem structure with this word.   
  5526. \ Put checkmark beside item# 2 .  
  5527. CHECKED 2 MAINMENU  EZMENU.SET.FLAG 
  5528. EZMENU.SETUP  ( name0 menu# &ezmenu -- ,Set default values)  
  5529. This word initializes the values in the Menu, MenuItem, and IntuiText structures associated with an EZMenu.  It then links together all the pieces for Intuition to use.  It must be executed after EZMENU.ALLOC and before any calls to EZMENU.TEXT! , EZMENU.SET.FLAG, EZMENU.COMMSEQ! , etc. The first parameter is a NUL terminated string that is the name for the menu.  The second parameter is the menu's intended position in the MenuStrip.  Remember the first menu is number 0.   You may want to change the default settings before calling this routine.  See below.
  5530. EZMENU.SUBMENU! ( &submenu item# &ezmenu -- )
  5531. Set submenu for this item.  The example in JD:DEMO_MENUS uses submenus.
  5532. EZSUBMENU.SETUP ( &ezmenu -- , set defaults and links ) 
  5533. EZMENU.SETITEM  ( 0name cfa char|0 item# &ezmenu -- ) 
  5534. Sets the name, cfa and command character for a menu item. Provided for convenience. 
  5535.  
  5536. EZMenu Default Settings
  5537. The EZMenu system uses default settings for many of the Menu and Menuitem parameters.  These are kept in variables that you can change before calling the EZMenu routines.
  5538. INTUITEXT-DEFLEFT ( --- addr ,default left edge of IntuiText item)
  5539. MENU-DEFLEFT  ( --- addr , default left edge of a menu )
  5540. MENU-DEFWIDTH  ( --- addr , default width of a menu )
  5541. MENUITEM-DEFLEFT  ( --- addr , default left edge of a menu item)
  5542. MENUITEM-DEFWIDTH  ( -- addr , default width of a menu item )
  5543.  
  5544. Low Level Menu Support    
  5545. The EZMenu system uses some of these words to perform it's functions. Several of these words will need to be called by your application directly.   
  5546. The following three words are used by EZMENU.SETUP to initialize the Amiga structures needed to use menus.   
  5547. INTUITEXT.SETUP  ( &intuitext -- , Set defaults for IntuiText)  
  5548. ITEMNUM()  ( menucode -- item# , parse code from event handler )  
  5549. MENU.LINKTO  ( menu1 menu2 -- , Make menu2 follow menu1 )  
  5550. A menustrip can be built by linking a number of menus together into a linked list.   
  5551. MENU.MIS># ( subitem# item# menu# -- menunum , Calc MENUNUM)  
  5552. Many Amiga routines use this compounded menu number.   
  5553. MENU.NTH    ( N &menustrip -- &Nth_Menu , Traverse Menustrip )  
  5554. Follows links in menustrip's linked list to find Nth menu.   
  5555. MENU.SETUP   ( name0 menu# &menu -- , Set defaults for Menu)  
  5556. See EZMENU.SETUP for description of parameters.   
  5557. MENUITEM.SETUP ( item# &menuitem -- , Set defaults for MenuItem)  
  5558. MENUNUM()  ( menucode -- menu# , parse code from event handler )  
  5559. SUBNUM()  ( menucode -- subitem# , parse code from event handler)  
  5560.  
  5561. The following words make calls to the Intuition library.   
  5562. SetMenuStrip()  ( &window &menustrip -- , Attach menus to window)
  5563. The menustrip is the address of the first menu in the linked list.   
  5564. ClearMenuStrip() ( &window -- , Remove the menus from a window.)  
  5565. OnMenu()  ( window menunum -- , Enable part of menu )
  5566. These routines are used when a menu is currently attached to a window.  The menunum can be created using MENU.MIS># .   
  5567. OffMenu() ( window menunum -- , Disable part of menu)
  5568. 20 -      EZMenu System
  5569.  
  5570.     EZMenu System    20 -  
  5571.  
  5572.  
  5573.  
  5574.  
  5575.  
  5576. Chapter 21
  5577. IFF Support
  5578. IFF files contain information that can be shared between various programs. Graphics and Animation programs on the Amiga save picture information in IFF files.  Thus you can save a picture from a paint program and use it in an animation program.  Music programs will save sound samples in IFF files The IFF standard was developed by Electronic Arts.   
  5579. JForth provides three levels of support for IFF files.  The lowest allows you to write a program that can read or write various IFF files.  The second level provides an easy system for reading and writing ILBM picture files.  The top level provides a rudimentary animation language based on the manipulation and display of images read from IFF files.   
  5580. IFF pictures can even be combined with free form graphics generated using the graphics library for some very special custom effects.  An example application, JSHOW, is included to show you how  to open a custom screen and display pictures from a file.  If you are not interested in the IFF picture files, you may want to skip ahead to the section on the IFF file format.   
  5581. We do not provide high level support for 8SVX sample files but this could be written using the IFF tools.  We do not imagine that this system will serve all the needs of all the people.  We have, however, tried to provide tools that are flexible enough so that others can use them.  Our main intent here is to provide you with a starting point for developing your own code.  All the IFF source code is in the directory JIFF:.  I urge you to print it out, study it, modify it and make it your own.
  5582. Description of Files in JIFF:  
  5583. PICTURES -  High level system for loading and displaying IFF pictures. This words could be used as the basis for a bitmapped animation system. You can combine these words with the normal graphics calls for custom effects.  If you want to save your resulting animation to give to friends, Clone it!  
  5584. PIC_EFFECTS - Special effects using Pictures - Wipe and Fadein, Fadeout.   
  5585. PIC_FLIP - Flip a picture about x,y or diagonally.
  5586. ILBM_PARSER - Tools for parsing an ILBM bitmap.   
  5587. ILBM_MAKER - Tools for writing a bitmap as an ILBM IFF file.   
  5588. SHOW_IFF - Display tools, application for displaying IFF files.   
  5589. IFF_Support - This file contains the core words for parsing an IFF file. It has tools for reading and writing chunks, and processing special chunks like 'FORM'.   
  5590. PACKING - Low level support for packing picture data into ILBM form. Support for run length encoding a Bitmap and converting a CTABLE to a CAMP.   
  5591. UNPACKING - Routines for unpacking data from an ILBM IFF file.   
  5592. IFF.J - Definition of BitMapHeader structure and the common chunk IDS.   
  5593. Tutorial 1 - Displaying Pictures   
  5594. First let's compile the IFF code and display a simple picture.  We provide an IFF picture, 2 brushes and an animbrush in the directory JPics:.  
  5595. Enter:  
  5596. INCLUDE JIFF:SHOW_IFF
  5597. JSHOW JPICS:MOUNTAINS.PIC 
  5598. JSHOW will read your file, open a screen, and display the picture.  Click in the top left corner when you are done looking.  (The images provided with JForth were chosen for their small size when compressed and not on artistic merit, as you will see.) 
  5599. Tutorial 2 - The Picture System
  5600. Now let's get fancy with bitmaps.  We will use the highest level - the "JForth IFF Picture System".  As a first step, let's load a picture to use as our background.  We can use the same picture of mountains.  Enter:  
  5601. INCLUDE JIFF:LOAD_PIC 
  5602. GR.INIT   \ Open Graphics and Intuition libraries
  5603. PICTURE BACKG  ( declare structure ) 
  5604. " jpics:mountains.pic" BACKG $PIC.LOAD? .
  5605. The second line declared a picture structure that is used to keep track of pictures that are loaded into the system.  You can declare as many of these structures as you need.  The third line loaded the graphics from the file "jpics:mountains.pic" and stored it "in" the Picture structure called BACKG.  A zero should have been returned from this word if everything went OK.  The FIRST picture loaded always causes a screen to open with the proper resolution and depth to display that picture.  It is important that this first picture be a full screen picture representative of the resolution you will be using in your program.   
  5606. You should now see your picture.  You can move between screens by hitting these key combinations: <left-Amiga-N> to get the workbench screen, <left-Amiga-M> to get other screens.  You might now want to shrink your JForth window and pull your workbench screen down a bit (grab it at the top) so you can see both screens.  Click in the JForth window, then enter:  
  5607. PICTURE MYSHIP 
  5608. " jpics:ship.br" MYSHIP $PIC.LOAD? . ( read bitmap ) 
  5609. With the above commands, we read the JPICS:SHIP.BR brush into a bitmap and saved the pointer to the bitmap in the structure MYSHIP.   
  5610. Let's draw our ship in the screen.  Enter:  
  5611. 20 30 MYSHIP PIC.BLIT 
  5612. Click over to the screen with the mountains on it.  You will probably see a rectangular block near the top left of the screen.  Inside the block will be the ship.  (The word "BLIT" is computerese for Block Transfer of Pixels.  This means one image is drawn in another.)  
  5613. The black rectangle is not a bug.  Bitmaps are rectangular and when you just draw them using PIC.BLIT you get the whole thing.  Luckily there is a way to copy a bitmap while keeping the background of the bitmap transparent.  This will be more like what you would see when you draw with a brush in a paint program.   
  5614. To copy a bitmap transparently we need to use a shadow mask of that bitmap.  A shadow mask is a special kind of bitmap that has only one real memory plane.  It is designed to look as if it has several planes.  When you blit another bitmap into it, any color other than 0 will turn on the pixel in the shadow mask.  This shadow mask is then used to cut a hole in the destination bitmap.  The picture can then be placed into that hole using an OR mode Blit.  The picture system will make a shadow mask for you automatically if you try to do a transparent blit.   
  5615. 120 40 MYSHIP PIC.TRANS.BLIT 
  5616. If you look at the picture now you should see another ship but without the rectangle.   
  5617. Drawing a Portion of a Picture  
  5618. For this next exercise we would like to have two pictures so let's modify the picture called BACKG to look different, then load another copy of our mountains.  To change BACKG, let's draw a big rectangle in it.  Enter (exactly):
  5619. 4 GR.COLOR!
  5620. 10 10  310 190 GR.RECT
  5621. There should now be a big rectangle in the middle of the picture.
  5622. Now let's reload up our mountains in another PICTURE for these next exercises.
  5623. PICTURE MNTNS 
  5624. " jpics:mountains.pic" MNTNS $PIC.LOAD? . 
  5625. Note: You will not see the new mountains picture.  We are still displaying the modified BACKG picture.
  5626. We can use the picture system to draw only a portion of a bitmap.  Suppose we want to take part of the top left of the mountain scene and draw it to the middle of the background.  Enter:  
  5627. 100 80 MNTNS PIC.PUT.WH 
  5628. This sets the width and height of the region to be drawn from. Enter:  
  5629. 120 70 MNTNS PIC.BLIT 
  5630. You should now see the top left corner drawn in the middle of the screen. We can set the corner of our region anywhere in the picture. Enter:  
  5631. 200 100 MNTNS PIC.PUT.XY 
  5632. 0 0 MNTNS PIC.BLIT 
  5633. You should now see a 100 by 80 pixel rectangular portion of the lower right of the mountain scene drawn at 0,0 on the screen.
  5634. This diagram shows the source region in a picture called Source and the region it is Blitted to in a picture called Destination.
  5635.  
  5636. Special Effects - Wipes and Fades 
  5637. We can do a few special effects that might be useful in constructing a video. Remember the composite output of your Amiga can be plugged into a VCR and recorded! To fade to black and then come back with another picture.  Enter:  
  5638. 4 BACKG PIC.FADEOUT 
  5639. PIC-START-BLACK ON   ( make MNTNS start black )  
  5640. MNTNS PIC.DISPLAY 
  5641. 8 MNTNS PIC.FADEIN 
  5642. This is a gentle way to transition between two scenes.  The command PIC.DISPLAY makes the specified picture be visible. [Hacker's note - this works by copying pointers to that picture's bit planes to the open screen's bitmap.]  The word PIC.FADEOUT and IN take a time parameter and a picture address.  The time parameter is the number of frames to wait before each change in brightness.
  5643. In this system we distinguish between the picture being displayed and the picture being drawn into.  This allows us to do what is called double buffering which is a way to eliminate some of the jitters in animation.  We are displaying the MNTNS picture but we are still drawing into the BACKGROUND picture.  Let's draw into the BACKGROUND using the Graphics toolbox then rapidly switch display buffers.  Enter:  
  5644. 23 45 " Peace On Earth" GR.XYTEXT 
  5645. If you look on the screen, you WON'T see this text.  Now enter:  
  5646. BACKG PIC.DISPLAY 
  5647. We can do another effect called a wipe that is used as a transition between pictures.  You may want to resize the JForth window then pull down the Workbench screen so that you can see the graphics screen as well.  Watch the screen and enter:  
  5648. MNTNS PIC.WHOLE ( reset source window to whole picture )
  5649. 0 0 2 WIPE_RIGHT MNTNS PIC.WIPE 
  5650. This told the Picture system to "wipe" the MNTNS picture into the current picture being drawn to.  The 0,0 was the x,y of the top left corner.  The 2 was the number of lines to blit per frame.  The WIPE_RIGHT parameter was the direction.  You can also choose between WIPE_LEFT, WIPE_UP, and WIPE_DOWN.  You can wipe with part of a picture by setting the region with PIC.PUT.WH and PIC.PUT.XY.   
  5651. Moving a Brush, Restoring the Background
  5652. Let's reload the MNTNS picture so that we have a clean slate. Enter:
  5653. " jpics:mountains.pic" MNTNS $PIC.LOAD? . 
  5654. MNTNS PIC.DISPLAY
  5655. MNTNS PIC.DRAWTO
  5656. Suppose we wanted to make a brush move smoothly across the screen.  We would need to draw it at one location, then draw it again moved slightly in the direction of motion, and so on.  If we do this, however, we end up with a trail of brushes.  Obviously we must erase one image before we draw the next.  How can we do that?  There are basically two ways.  One is to rebuild the entire image by copying in a fresh image of the background that was saved away, then drawing the brush in the new position.  This assumes that you have a copy of the background saved.  If that is not that case then you will need method number two.
  5657. In this method we save a small portion of the background, just the amount that will be covered when we draw our brush.  To erase our brush we can then copy this saved portion back to its original location.
  5658. Let's try this with our ship.  First we must allocate a bitmap for this backup image.  Enter:
  5659. 0 MYSHIP PIC.ALLOC.BACKUP? .  \ must be zero
  5660. A zero is passed as the first parameter to select between backup image number zero or one.  These two backups come in handy when doing double buffering because the brush appears in two backgrounds 
  5661. Now let's make a backup copy under our brush, then draw the brush. Enter:
  5662. 20 45 0 MYSHIP PIC.BACKUP.NTH  \ no visible change
  5663. 20 45 MYSHIP PIC.BLIT     \ must be to same X,Y
  5664. Now to move the brush we must first restore the old background. Enter:
  5665. 0 MYSHIP PIC.RESTORE.NTH
  5666. Notice that the background is restored.and we can redraw the brush in a new location.  Enter:
  5667. 24 53 0 MYSHIP PIC.BACKUP.NTH
  5668. 24 53 MYSHIP PIC.BLIT
  5669. By continuing in this manner, a brush can be made to move across the screen.
  5670. If you are moving multiple brushes in an image that might overlap, you must follow a simple rule:
  5671. For multiple brushes, call PIC.RESTORE.NTH in the opposite order that you call PIC.BACKUP.NTH.
  5672. Otherwise you will not restore the image properly.
  5673. Cleaning Up
  5674. We must now cleanup the allocated memory, close the screen.  Enter:  
  5675. MNTNS PIC.FREE 
  5676. BACKG PIC.FREE 
  5677. MYSHIP PIC.FREE 
  5678. Whichever picture is currently being displayed will close the screen when freed  When finished using the graphics toolbox, we should close the Graphics and Intuition library be entering:
  5679. GR.TERM
  5680. For more examples of using the picture system, look at our simple test program: JIFF:TEST_PIC.
  5681. Picture System Reference
  5682. The Picture System provides easy to use routines for displaying and manipulating images read from IFF ILBM files. It can be loaded by entering:
  5683. INCLUDE JIFF:LOAD_PIC
  5684. Error Handling
  5685. Many of the routines return an ERROR? flag that is non-zero if there was an error.  Your program should always check this flag when it is returned.  The most common sources of errors would be if memory could not be allocated for an operation, or if there was a problem with a file.  Well written applications should expect these errors to occur periodically and to respond gracefully when they do.  Do not simply ABORT because your user might lose valuable work in progress.  See the documentation for GOTO.ERROR for tips on handling errors.
  5686. Double Buffering
  5687. Double buffering is a technique used to achieve smooth animations.  The basic sequence of operations is:
  5688. Display Buffer 0
  5689. Draw to Buffer 1
  5690. Display Buffer 1
  5691. Draw to Buffer 0
  5692. Repeat
  5693. In this manner the viewer always sees a static image while the other image is being drawn.
  5694. There are three ways to do double buffering provided by JForth, each with their own advantages and disadvantages.  You can also develop your own system if none of these suit your needs.
  5695. 1) Use the tools in JIFF:DOUBLE_BUFFER.  These are demonstrated in JD:DEMO_DBUF.  The advantage of these is that they are independent of the PICTURE system, and are very convenient.
  5696. 2) Use PIC.VIEW to switch displays.  This switches very fast because it uses LoadView() and is very convenient when using the PICTURE system.  The disadvantage is that it works below the level of Intuition so mouse input may not go where you think it will.  Be sure to bring your screen to front before calling this or else your mouse input may go to another screen. To bring the screen that the PICTURE system uses to the front, enter:
  5697. SIFF-SCREEN @ ScreenToFront()
  5698. 3) Use PIC.DISPLAY to switch displays.  This works well with Intuition but is quite slow.  It takes about 2-3 frames just to switch displays compared to PIC.VIEW which is virtually instantaneous.
  5699. Using your Own Display Screen
  5700. The PICTURE system uses the screen pointed to by the variable SIFF-SCREEN.  If you load a picture using $PIC.LOAD? and there is no screen, a screen will be opened for you and its address placed in SIFF-SCREEN.  If you want to use your own screen, open it before calling $PIC.LOAD? and place your screen address in SIFF-SCREEN.
  5701. Clipping with Pictures
  5702. There are two types of clipping involved with the Picture system.  If you draw to the picture that initiated the opening of the screen, then all graphics operations will be clipped to the BACKDROP window in that screen.  This includes calls to PIC.BLIT and other calls like GR.DRAW or GR.TEXT.  If, however, you call PIC.DRAWTO to draw to another picture, then only PIC.xxx calls will be clipped.  Line drawing using GR.DRAW and similar calls will not be clipped and could result in the trashing of memory.  This is because the RastPort of the BACKDROP window has a ClipRect but the RastPort for a picture does not.  The PIC.xxx calls are clipped using a custom clipping routine designed for rectangular blits.  By setting the variable PIC-CLIPPING OFF you can turn off this custom clipping.
  5703. All drawing is directed to the RastPort whose ABSOLUTE address is in the variable GR-CURRPORT.  This can be set directly or by using GR.SET.CURWINDOW.
  5704. Picture Glossary      
  5705. JIFF:PICTURE
  5706. $PIC.LOAD? ( $filename picture  -- error? , load IFF picture )  
  5707. Load an IFF ILBM picture from a file to a picture.  The first one loaded will open an appropriately sized screen for display.  Make sure, therefore, that the first picture loaded is a full screen picture that is the right resolution for the rest of your animation.  You might want to load a title screen first.  Set the variable PIC-START-BLACK to TRUE if you want this one to start black.  You can then fade in using PIC.FADEIN .   
  5708. $PIC.SAVE? ( $filename picture  -- error? )  
  5709. Save the contents of a picture in an IFF ILBM file for use with other graphics applications.  The bitmap will be compressed using run length encoding. 
  5710. PIC-CLIPPING ( -- addr )
  5711. When this variable is set TRUE, then PIC.BLIT and PIC.TRANS.BLIT will be clipped to the edges of the destination picture.  This may be redundant if drawing to a window with Amiga based clipping.
  5712. PIC-START-BLACK  ( -- addr , variable to control color )  
  5713. If this variable is set TRUE, then $PIC.LOAD? and PIC.DISPLAY will set the screen to all black.  You can then use PIC.FADEIN to make the picture visible.   
  5714. PIC.?BREAK  ( -- , OBSOLETE, don't use )  
  5715. PIC.ALLOC.BACKUP?  ( backup# picture -- error? ) 
  5716. Allocate a bitmap to use with PIC.BACKUP.NTH.  Backup# is 0 or 1. 
  5717. PIC.ALLOC.SHADOW? ( picture -- error? ) 
  5718. Allocate a shadow mask bitmap for use with PIC.TRANS.BLIT. You must also call PIC.CAST.SHADOW before calling PIC.TRANS.BLIT. 
  5719. PIC.ALLOC.VIEW? ( picture -- error? ) 
  5720. Allocate a VIEW for PIC.VIEW. 
  5721. PIC.BACKUP.NTH ( dstx dsty backup# pict -- ) 
  5722. Backup part of the image that will be overwritten when we do a PIC.BLIT or PIC.TRANS.BLIT at the same DSTX and DSTY. That image can then be restored using PIC.RESTORE.NTH. This is used mostly when using a moving brush. Backup# is 0 or 1. 
  5723. PIC.BLIT ( xd yd picture -- , blit to x,y )  
  5724. Blit the bitmap of a picture into the current rastport at xd,yd.  The current rastport is the one whose absolute address is in GR-CURRPORT . PIC.DRAWTO can be used to select a picture to BLIT into.  By BLITting a series of related pictures you can obtain smooth animation effects.   
  5725. PIC.BUILD  ( bitmap picture -- , build a picture from scratch )
  5726. If you want to use a bitmap that does not come from an IFF file as a picture, use this word.  The bitmap should already be initialized and have an image associated with it.
  5727. PIC.CAST.SHADOW ( picture --  ) 
  5728. Create a shadow mask by ORing each plane of a picture into a single plane.  You should call this routine anytime you change a picture that you use with PIC.TRANS.BLIT. 
  5729. PIC.CLOSEBOX ( -- , OBSOLETE, don't use )  
  5730. PIC.COPY ( srcpic dstpic -- , copy bitmaps and color table )  
  5731. Copy the contents of one picture to another.  The second picture must be the same size as the first.  Use PIC.DUPLICATE to allocate a same sized picture first if needed.   
  5732. PIC.DISPLAY ( picture -- , display picture by copying bitmaps )  
  5733. Causes this picture to be the current one displayed.  Use this with PIC.DRAWTO for double buffering.  Loads pointers to this picture's bitmap planes into the SIFF screen's bitmap.   
  5734. PIC.DRAWTO ( picture -- , make this the destination )  
  5735. Sets the JForth graphics variable GR-CURRPORT to point to this picture's Rastport (absolute address).  Now PIC.BLIT, PIC.WIPE, etc. and all GR.xxx commands will draw into this pictures bitmap.  You can draw into one picture while displaying another for a double buffering effect.   
  5736. Warning:  Pictures do not have clipping layers in their RastPorts. Thus any line drawing or other graphics operations may extend beyond the edges of the pictures and overwrite memory.  PIC.BLIT and PIC.TRANS.BLIT will continue to be clipped as long as PIC-CLIPPING is set TRUE.
  5737. PIC.DUPLICATE?  ( srcpic dstpic -- error? , )  
  5738. Take an empty picture and allocate bitmaps for it the same size as the source picture.  Then call PIC.COPY to copy the bitmap contents.
  5739. PIC.FREE  ( picture -- , free all parts of picture )  
  5740. Free all allocated internal data.  This MUST be called when you are completely through using a picture.  The picture that is currently being displayed via PIC.DISPLAY will close the SIFF screen when this word is called.   
  5741. PIC.GET.DEPTH ( picture -- depth , number of planes )  
  5742. PIC.GET.WH ( picture -- w h , fetch source w and h )  
  5743. PIC.GET.XY ( picture -- x y , fetch source x and y )  
  5744. PIC.GET.XYOFF ( picture -- x y , fetch dest x and y )
  5745. PIC.MAKE? ( colrtab|0 #colors deep wide high pict -- error? ) 
  5746. Create bitmaps and other necessary structures for a picture based on input parameters.  This is an alternative to $PIC.LOAD?. COLRTAB can be zero or the address of a color table whose contents will be copied to a newly allocated color table. 
  5747. PIC.OPEN? ( picture -- screen | 0 ) 
  5748. Open a screen based on the picture. 
  5749. PIC.PUT.WH ( width height picture -- , set source width, height )  
  5750. Sets the width and height of a rectangular portion of a picture.  This is what will be drawn using PIC.BLIT and PIC.WIPE.   
  5751. PIC.PUT.XY ( x y picture -- , set source x and y )  
  5752. Set the top,left x,y of a rectangle to draw from.  Used with PIC.PUT.WH .   
  5753. PIC.PUT.XYOFF ( x y picture -- , set dest x and y )
  5754. When this picture is drawn with PIC.BLIT or PIC.TRANS.BLIT, the destination x,y will be offset using these values.  This can be used to "center" a picture so that the coordinates you pass to PIC.BLIT determine where a certain part of a bitmap will land other than the top,left corner.
  5755. PIC.RESTORE.NTH ( backup# picture -- )
  5756. Restore the part of the image saved using PIC.BACKUP.NTH. 
  5757. PIC.TRANS.BLIT ( xd yd picture -- , blit transparently )  
  5758. Copy a bitmap into the current rastport using a transparent background. This is useful when using brushes from a point program.  If you are drawing a head then you just want the round part superimposed over the background. Without transparency, you would get a black rectangle with a head in the middle! This routine uses a shadow mask rastport.  The mask is used to punch a hole in the background where there is data in the picture.  It then ORs the bitmap with the rastport.  The opaque pixels in the bitmap will line up with the black hole in the background.  The transparent black pixels in the bitmap will line up with remaining pixels in the background. When you or these you get a nice superimposition of the bitmap over the rastport.   
  5759. PIC.USE.COLORS ( picture -- , apply colors to screen )  
  5760. Use the color table from a picture in the SIFF screen.   
  5761. PIC.VIEW ( picture -- ) 
  5762. Displays a picture by calling LoadView().  This will call PIC.ALLOC.VIEW? just in case it hasn't been called yet.  This is faster than PIC.DISPLAY but Intuition will not realize the display has changed. This can cause unexpected results. If, for example, the Workbench screen was showing before this call, mouse clicks will still go to the Workbench even though this picture is showing in front. 
  5763. PIC.WHOLE ( picture -- , reset bounds to use whole picture)  
  5764. Resets the source x,y and w,h to the full picture boundaries.   
  5765.  
  5766. JIFF:PIC_EFFECTS
  5767. PIC.BRIGHTNESS ( level picture -- , scale colormaps )  
  5768. Set the SIFF screen brightness by scaling the color map in a picture.  The range is zero to 16 where 16 is full brightness.   
  5769. PIC.FADEIN ( frames picture -- , fade in from black )  
  5770. Call PIC.BRIGHTNESS in a loop from 0 to 16.  The frames parameter determines how many video frames to wait between successive level changes. A value of 4 is nice.   
  5771. PIC.FADEOUT ( frames picture -- , fade to black )  
  5772. PIC.NEXT.WIPE ( picture -- done? )  
  5773. Draw next portion of a wipe based on PIC.SETUP.WIPE call.  Call this in a loop until it returns true.  It doesn't hurt to call it after it's done.   
  5774. PIC.ROTATE ( -- , rotate siff-screen )  
  5775. Rotate the plane pointers in the SIFF screen. Causes wild color changes. Do it as many times as there are planes if you want to get back to the same color.  Use PIC.GET.DEPTH to find the number of planes.   
  5776. PIC.SETUP.WIPE ( xd yd nlines direction picture -- )  
  5777. Set up a picture for a wipe effect.  The data will be taken from the source rectangle and drawn to where xd,yd is at the top,left corner.  You can specify the number of lines per wipe pass.  The more lines the faster the wipe.  Try to make it divide evenly into the number of lines total.  The direction parameter can be one of four values:  
  5778. WIPE_LEFT  WIPE_RIGHT  WIPE_UP  WIPE_DOWN 
  5779. WIPE_LEFT will cause to wipe to progress from right to left.  You may setup several pictures then call PIC.NEXT.WIPE for each one in a loop to have simultaneous wipes happening in parallel.   
  5780. PIC.WIPE ( xd yd nlines direction pict -- , wipe a picture )  
  5781. Call PIC.SETUP.WIPE then loop on PIC.NEXT.WIPE until done.   
  5782.  
  5783. JIFF:PIC_FLIP 
  5784. PIC.FLIP.X  ( picture -- ) 
  5785. Flip a picture horizontally. 
  5786. PIC.FLIP.Y  ( picture -- ) 
  5787. Flip a picture vertically. 
  5788. PIC.FLIP.DIAG  ( picture -- ) 
  5789. Flip a picture about a line drawn from two diagonal corners. 
  5790. IFF File Support
  5791. (For a more detailed description of IFF, please see the ROM Kernal Manual Volume 2)  
  5792. IFF files are made up of "chunks".  A chunk has 3 parts:  
  5793. 1) Chunk ID - 4 characters, eg. 'FORM', 'BMHD' 
  5794. 2) Chunk Size - in bytes 
  5795. 3) Chunk Data - whatever 
  5796. The chunk ID tells a program what kind of chunk it is.  For example, 'CMAP' means that the chunk is a color map for a picture.  A chunk ID consists of 4 character packed into a 4 byte integer.  The second part, the chunk size, tells you how many bytes are in the data portion.  (If there are an odd number of data bytes, a pad byte will be added so that the next chunk starts on an even boundary.) The data portion is where the actual pictures, samples, note lists, etc. are stored.   
  5797. There are several Chunk IDs which are considered special.  These chunks can contain other chunks in their data portion.  They are FORM, LIST and CAT. An IFF file consists of one of these 3 chunks containing one or more sub chunks.  FORM chunks are the most common of the 3.  The data portion of a FORM consists of a FormType followed by a number of subchunks.  One common FormType is 'ILBM' which means that the FORM contains chunks that describe an InterLeaved BitMap, or picture.  The chunks that describe a picture include 'BMHD', or BitMapHeaDer, which tells you how many pixels high and wide a picture is, how many bit planes it has, where it is positioned on the screen, etc.  Another chunk in an ILBM is the 'BODY' that contains the actual pixels of the picture.  These are often compressed to save space on the disk.   
  5798. How JForth Handles IFF files   
  5799. When you open an IFF file, you really don't know what kind of chunks you will find inside.  To read an IFF file, therefore, you must be prepared to handle anything you find.   
  5800. JForth provides a word called IFF.SCAN that reads the chunk headers and eats its way through an IFF file to see what chunks are there.  It uses the chunk size to move from one chunk to the next.  Once it has the chunk ID and size it passes these to the deferred word IFF.PROCESS.CHUNK. IFF.PROCESS.CHUNK can then check to see if it is a special type of chunk, ie. a 'FORM', 'LIST' or 'CAT'.  This can be done by calling IFF.SPECIAL? which will process the special chunk if it is one.  IFF.SPECIAL? returns a flag that tells IFF.PROCESS.CHUNK whether the chunk has already been processed.  If not IFF.PROCESS.CHUNK can do whatever it needs to for that chunk.  You can set this word to be anything you want and thus control how the IFF file is processed.  There are several chunk processors to parse ILBM files, or to print an outline of chunks in the file.   
  5801. Tutorial 3 - Vectored Parsing of IFF Files   
  5802. In the previous tutorial, we used the existing ILBM parser to display an IFF picture.  Let's now write our own custom parser.   
  5803. (The parsing of IFF files is done using deferred words.  If you are not familiar with DEFER, please see the section on DEFER in this manual.)  
  5804. IFF.PROCESS.CHUNK is the most important deferred word in this system.  Its stack diagram is:  
  5805. IFF.PROCESS.CHUNK ( size chkid -- ) 
  5806. Printing Chunk Headers     
  5807. It is called by IFF.SCAN which is called by IFF.DOFILE.  We can write a word to be executed when IFF.PROCESS.CHUNK is called.  Let's first write a simple word to print out the header of a chunk.  We have a word called .CHKID that will print a packed 4 character chunk ID so let's use it. Enter:  
  5808. : SHOW.CHUNK  ( size chkid -- ) 
  5809.         .CHKID SPACE . CR 
  5810. 20 'BMHD' SHOW.CHUNK 
  5811. Now let's use this to examine our MOUNTAINS file.  Make sure you are in the same directory as your MOUNTAINS file then enter:  
  5812. ' SHOW.CHUNK IS IFF.PROCESS.CHUNK 
  5813. 20 'BMHD' IFF.PROCESS.CHUNK 
  5814. IFF.DOFILE MOUNTAINS 
  5815. Notice that the chunk in the file is a FORM chunk.  Where are the other chunks, the BitMapHeader (BMHD) or the pixels (BODY)? They are nested inside the FORM chunk.  To parse an IFF file we need to have a recursive parser.  This is easier than it sounds.  We have a special word for handling chunks like FORM, LIST and CAT called IFF.SPECIAL? It's stack diagram is:  
  5816. IFF.SPECIAL? ( size chkid -- handled? ) 
  5817. If the chunk is a special recursive chunk, this word will handle it and return TRUE.  Other wise it will return FALSE.  To handle a special chunk IFF.SPECIAL? calls IFF.SCAN which in turn calls IFF.PROCESS.CHUNK .  Enough talk, let's show we can use this in our code.  Enter:  
  5818. : NESTED.SHOW ( size chkid -- ) 
  5819.         2DUP IFF.SPECIAL? 
  5820.         IF 2DROP  ( we can ignore it ) 
  5821.         ELSE SHOW.CHUNK 
  5822.         THEN 
  5823. ' NESTED.SHOW IS IFF.PROCESS.CHUNK 
  5824. IFF.DOFILE MOUNTAINS 
  5825. We should now see all the chunks in the file listed.  We have a word already written that does the above using IFF-NESTED to show the recursive nature of the file.  ("Now he tells me!") Try:  
  5826. IFF.CHECK MOUNTAINS 
  5827. This word can be cloned if you want it.   
  5828. Parsing ILBM FORMs     
  5829. JForth provides tools specifically for parsing an ILBM form.  The word $ILBM.PARSE.FILE will scan a file for chunks.  The BitMapHeader is copied to a structure called ILBM-Header.  This contains information used to decipher the rest of the file.  The packed BODY chunk and the CMAP chunk are read into allocated memory, and their pointers left in the variable ILBM-BODY and ILBM-CMAP.  GRAB chunks and CAMG chunks are read directly into variables called ILBM-GRABXY and ILBM-CAMG.  When the parser is finished you can pull values from these storage locations and build a display.  Look in the file JIFF:SHOW_IFF for examples of how this is done.   
  5830. Also take a look at the file JA:DumpIFF.f which prints the contents of an IFF file for analysis.
  5831. IFF Support Glossary
  5832. JIFF:ILBM_PARSER       
  5833. $ILBM.PARSE.FILE? ( $filename -- error? , parse an IFF file )  
  5834. Parse an ILBM file based on whatever is in IFF.PROCESS.CHUNK.  Uses $IFF.DOFILE.  Use ILBM.PARSE.INIT to initialize IFF.PROCESS.CHUNK if you have changed it and want to use the original ILBM parser.   
  5835. HEADER>BITMAP ( bitmapheader -- bitmap | 0 , allocate bitmap)  
  5836. Allocate a properly sized bitmap based on the contents of the BitMapHeader structure.   
  5837.  
  5838. These next few variables and structures are set by the ILBM Parser as it reads an IFF file.  Look in here for the information found.   
  5839. ILBM-BODY  ( -- var-addr , holds pointer to allocated 'BODY' )  
  5840. ILBM-BSIZE ( -- var-addr , holds size of 'BODY' )  
  5841. ILBM-CAMG  ( -- var-addr , holds viewmodes from any 'CAMG' chunk)  
  5842. ILBM-GRABXY ( -- var-addr , holds packed 16 bit x,y from 'GRAB' )  
  5843. ILBM-CMAP  ( -- var-addr , holds pointer to allocated 'CMAP' )  
  5844. ILBM-CMSIZE ( -- var-addr , holds size in bytes of CMAP )  
  5845. ILBM-HEADER  ( -- addr , handy BitMapHeader structure )  
  5846. The ILBM Parser fills this structure with information from the 'BMHD' chunk.  Read the IFF.J file for a list of members.   
  5847. ILBM.ALLOC.BITMAP ( -- bitmap | 0 )  
  5848. Allocate a bitmap of the appropriate size and depth based on the information in the ILBM-Header.  This bitmap will be used to receive the bitmap as it is unpacked from the 'BODY' chunk.  Calls HEADER>BITMAP.   Returns zero if the bitmap could not be allocated.
  5849. ILBM.CLEANUP ( -- , free any data allocated )  
  5850. Free BODY and CMAP chunk memory allocated by ILBM.HANDLER.   
  5851. ILBM.FILL.BITMAP ( bitmap -- bitmap | 0)  
  5852. Unpack the body pointed to by ILBM-BODY into the bitmap.  Returns 0 if there is an unpacking error.   
  5853. ILBM.PARSER ( size chkid -- , default handler used to parse ILBM)  
  5854. IFF.PROCESS.CHUNK is set to call this word by ILBM.INIT.  BMHD chunks are copied to ILBM-HEADER , a BitMapHeader structure.  BODY and CMAP chunks are read into an allocated memory area whose address is stored in ILBM-BODY or ILBM-CMAP.  GRAB chunks are read into the ILBM-GRABXY variable.  CAMG chunks are read into the ILBM-CAMG variable.  Any other chunks are passed to the deferred word ILBM.OTHER.HANDLER for custom processing.   
  5855. ILBM.INIT ( -- , set vectors )  
  5856. Set IFF.PROCESS.CHUNK to ILBM.HANDLER and set ILBM.OTHER.HANDLER to IFF.NOT.PROC .   
  5857. ILBM.MAKE.BITMAP ( body bsize bmheader -- bitmap | 0 )  
  5858. Allocate and fill a bitmap based on body and BitMapHeader.   
  5859. ILBM.MAKE.CTABLE  ( -- ctable num_colors  ) 
  5860. Allocate a color table based on the information in the CMAP chunk.  Return two NULLs if there was no CMAP or it couldn't be allocated.
  5861. ILBM.OTHER.HANDLER  ( size chkid -- , handle other chunks)  
  5862. Deferred word called by ILBM.HANDLER when it sees a chunk it doesn't handle, 'CRNG' for example.   
  5863.  
  5864. JIFF:ILBM_MAKER       
  5865. ILBM.HEADER.SETUP  ( bitmap bmapheader -- , set w,h and depth )  
  5866. Setup BitMapHeader structure values based on the bitmap.   
  5867. ILBM.WRITE.BITMAP?  ( bitmap -- error? )
  5868. Write as a BODY chunk to the currently open IFF file.  
  5869. ILBM.WRITE.ILBM?  ( bmap ctable ctable# -- error? )
  5870. Write a bitmap and a ctable to an IFF file. You must call $IFF.OPEN first then call IFF.CLOSE.  This is to be considered as an example program.  You will probably want to make a copy of this in another file and modify it to suit your purposes.   
  5871. $SCREEN>IFF?  ( screen $filename -- error? )
  5872. This handy word pulls the bitmap and colortable from a  screen and writes an IFF file.
  5873.  
  5874. JIFF:SHOW_IFF       
  5875. Most of these words use the screen pointed to by the SIFF-SCREEN variable.   
  5876. $IFF>BITMAP ( $filename -- bitmap | 0)  
  5877. Read a file, allocate a bitmap and load it with the picture in the file. You can use this bitmap as a brush or whatever.  You must use FREE.BITMAP from JU:GRAPH_SUPPORT to free this bitmap when done.   
  5878. $IFF>DISPLAY ( $filename -- bitmap | 0 , display iff on screen )  
  5879. Read an IFF file, open an appropriate screen and display the picture.  The screen address will be in the variable SIFF-SCREEN .  When done you should call SIFF.CLOSE and then use FREE.BITMAP to deallocate the bitmap you have been given.  Look at the source code for JSHOW. 
  5880. IFF>BITMAP ( <filename> -- bitmap | 0 , read IFF file )  
  5881. Reads filename from input stream and calls $IFF>BITMAP.   
  5882. IFF>DISPLAY ( <filename> -- bitmap | 0 , open screen and display)  
  5883. Reads filename from input stream and calls $IFF>DISPLAY.   
  5884. JSHOW  ( <filename> -- )  
  5885. Read the IFF file and display the picture.  Take down the picture when you click the topleft corner or hit a key.  This can be cloned for a handy IFF display program.   
  5886. SIFF-SCREEN ( -- addr , variable holding address of screen ) 
  5887. SIFF-WINDOW ( -- addr , variable holding address of window ) 
  5888. SIFF.BLACKOUT ( -- , black out colors on screen )  
  5889. SIFF.SHOWIT ( -- , Put window display in front for closebox.)  
  5890. SIFF.USE.CMAP ( cmap cmsize -- , use CMAP directly from IFF)  
  5891. Set colors in SIFF screen based on CMAP.   
  5892. SIFF.USE.CTABLE ( ctable #colors -- , use Amiga CTABLE )  
  5893. SIFF.CLOSE ( -- , Close SIFF screen and window.)  
  5894. SIFF.WAIT ( -- , Wait until CLOSEBOX or Keyboard is hit.)  
  5895. Low Level Support     
  5896. JIFF:IFF_SUPPORT
  5897. $IFF.DOFILE? ( $filename -- error? )
  5898. Process file using deferred words.  Open the file whose name is on the stack, pull out the chunks and call IFF.PROCESS.CHUNK after verifying that it is an IFF file.   
  5899. $IFF.OPEN?  ( $filename -- fileid | 0 )  
  5900. Open a file for IFF.READ and IFF.WRITE.  Set IFF-FILEID variable to file-pointer.   
  5901. .CHKID ( chkid -- , print a chunk id as 4 characters )  
  5902. IFF.BEGIN.FORM?  ( type -- start-position error? )  
  5903. Start writing an IFF 'FORM' chunk. An example of type is 'ILBM'.  The start position is saved for IFF.END.FORM.   
  5904. IFF.CHECK ( <filename> -- , print chunks )  
  5905. Set IFF.PROCESS.CHUNK to execute IFF.PRINT.CHUNK then call IFF.DOFILE. This results in a list of the chunks that are in an IFF file.  This is a handy tool that could be cloned.   
  5906. IFF.NOT.PROC ( size chkid -- , default for ILBM.OTHER.HANDLER )  
  5907. Prints a message that a chunk was not processed.   
  5908. IFF.PRINT.CHUNK  ( size chkid -- , print chunk id and size )  
  5909. IFF.PROCESS.CHUNK ( size chkid -- )  
  5910. This deferred word is called from IFF.SCAN when a new chunk is encountered in the file.  You can set it to your own word for customized parsing of IFF files.   
  5911. IFF.PROCESS.FORM ( size -- )  
  5912. This reads a 'FORM' chunk and processes all of the chunks it finds by calling IFF.PROCESS.CHUNK .   
  5913. IFF.READ ( addr #bytes -- #bytes , read from open IFF file)  
  5914. This uses the fileid obtained using $IFF.OPEN .   
  5915. IFF.READ? ( addr #bytes -- error?, read from open IFF file)  
  5916. Calls IFF.READ and returns ERROR? true if the number of bytes read does not the number of bytes requested.  
  5917. IFF.READ.CHKID  ( -- size chkid | 0 0 )  
  5918. Read the next 8 bytes in file assuming it is a chunk header. Return 0 0  if an error occurs.  
  5919. IFF.READ.DATA ( dsize -- addr | null , allocate space )  
  5920. Read DSIZE bytes from the IFF file into an allocated memory area.  Return NULL if couldn't allocate.  This is handy if you encounter a big chunk.   
  5921. IFF.READ.TYPE  ( -- typeid | 0 )  
  5922. Read the next 4 byte from the IFF file.  Used by words like IFF.PROCESS.FORM to check the FORM type.   Return zero if an error occurs.
  5923. IFF.SCAN ( -- size , read chunk header and doit)  
  5924. Read the next chunk header and pass it to IFF.PROCESS.CHUNK then move the file pointer past that chunk's data.   
  5925. IFF.SEEK ( position -- , move file pointer, "seek" )  
  5926. The next read or write will occur at this new position.   
  5927. IFF.SPECIAL? ( size chkid -- done? )  
  5928. Check to see if the chunk is one of the special type, ie.  'FORM', 'LIST', or 'CAT'.  If so process it and return true.  This calls IFF.SCAN which can result in recursion.  Increments IFF-NESTED to indicate depth of recursion.   
  5929. IFF.WHERE ( -- current_pos , in file )  
  5930. Where are we currently positioned in file?  
  5931. IFF.WRITE ( addr #bytes -- #bytes , write to open IFF file)  
  5932. Write data to file opened by $IFF.OPEN .   
  5933. IFF.WRITE? ( addr #bytes -- error? )  
  5934. Calls IFF.WRITE then checks to make sure the number of bytes written matches the requested number.  Note: the stack diagram for this word has changed since JForth V2.0.  See the note on incompatibilities at the end of this chapter.
  5935. IFF.WRITE.CHKID?  ( size chkid -- error? , write chunk header )  
  5936. Write an 8 byte chunk header using IFF.WRITE.   
  5937. IFF.WRITE.CHUNK?  ( address size chkid -- error? )
  5938. Write complete chunk to current file.  
  5939.  
  5940. JIFF:UNPACKING       
  5941. BODY>BITMAP  ( bodyptr bsize bmap compr -- bmap | NULL )  
  5942. Unpack a body into a bitmap using given compression mode.   
  5943. CMAP>CTABLE ( cmap ctable #entries -- , unpack )  
  5944. Convert an  IFF CMAP to an Amiga CTABLE array.   
  5945. UNPACKROW ( src dst #src #dst -- src' dst' #src' error? )  
  5946. Unpack a run length encoded row from source to destination.   
  5947.  
  5948. JIFF:PACKING
  5949. This is a new version of PACKING provided by Martin Kees.  It uses a virtual file system to write BODY chunks to a file as they are created.
  5950. CTABLE>CMAP ( ctable cmap #entries -- , pack )  
  5951. Convert a CTABLE array to an IFF CMAP.   
  5952. ILBM.MAKE.BODY ( bmap compr -- bodyptr bsize | -1 )  
  5953. Allocate a body memory area then pack the bitmap into it using the desired compression mode. Return -1 if an error occurs.   Uses the virtual file system to write to a RAM: based file, then reads it back.
  5954. WRITE.BITMAP.BODY { bmap ifffile compr -- bodysize | 0 }
  5955. Write a bitmap to a file as a BODY chunk.  It will be run length encoded if COMPR = 0.
  5956. JIFF:PACKING_OLD
  5957. This is the old version of the packing code that had problems with highly randomized pictures whose compressed form was larger than the original form.  Obsolete.
  5958. BITMAP>BODY  ( bmap bodyptr bsize compr -- bsize'|-1 )  
  5959. Pack a bitmap into a body using given compression mode.   
  5960. PACKROW ( src dst src# dst# -- dst' dst# error? )  
  5961. Pack a row of data using run length encoding.  This could be used for other than picture data!  
  5962. Incompatibilities with JForth V2.0
  5963. There have been some changes that may make code written using JForth 2.0 incompatible with JForth V3.0.   In version 2.0, when an error occurred, the deferred word IFF.ERROR was called which typically caused an abort.  This is fine when debugging but is totally unacceptable for a finished application.  A properly written application should test for possible errors and handle them gracefully.  The previous version did not allow programmers to do that.  We felt it was better to correct this problem than to perpetuate a mistake.  Unfortunately, some words have been changed.  Words that might fail due to insufficient memory or problems with a file now return an error flag.  We added a '?' at the end of their names to distinguish them from their original versions and to indicate that they return something of interest.  Examples are ILBM.WRITE.BITMAP? and $IFF.DOFILE?.  One notable exception to this is IFF.WRITE? which existed in V2.0 but did not return a flag.  The stack diagram for this word was actually changed so that it now returns an error flag.  I hated doing this but felt it was justified for the purpose of consistency.
  5964. Another incompatibility is that when $PIC.LOAD? is first called, the current RastPort is set to that of the backdrop window.  The advantage of this is that clipping is active for all graphics.  If you then call PIC.DISPLAY for another picture, graphics output will got to that picture as if you had called PIC.DRAWTO for that picture.  If you want graphic output to go to a specific picture you must call PIC.DRAWTO explicitly.  Be aware that only PIC.xxx calls are clipped after a call to PIC.DRAWTO.  See the section in this chapter on clipping for more information.
  5965. 21 -      IFF Support
  5966.  
  5967.     IFF Support    21 -  
  5968.  
  5969.  
  5970.  
  5971.  
  5972. Chapter 22
  5973. Anims and Animbrushes
  5974. by Martin Kees 
  5975. (This facility was contributed by Martin Kees.  We at Delta Research are very grateful to Martin for his generosity.  Martin also contributed code for the ARexx interface and assisted us greatly with beta testing.  Fred Fish disk 516 is all Martin's work. It includes a demo version of a CEL animation program called XL which allows "onion-skin" drawing of Animations. It also includes a fascinating puzzle called Enigma, a loom simulator for weaving design, and more. Watch for more great work from this talented programmer.) 
  5976. Introduction
  5977. Amiga programs use a standard IFF file format for exchanging graphic images. These include still pictures, animations, and animbrushes. This allows you to move images between drawing programs like DeluxePaint, presentation programs like Amiga Vision, image processing programs like Art Department Professional, and other programs. 
  5978. This toolbox provides routines that allow you to load animations and animbrushes, to play the animations and access the frames of an animbrush. Using JForth will allow you to control and coordinate an animated presentation at a very high level. 
  5979. You are encouraged to study the anim source code files, modify, and expand the code to meet your own needs.  If you wish to do a lot with animation you should consider upgrading your AMIGA in three ways: 
  5980. 1) Fast Memory Expansion
  5981. 2) Chip Memory expansion to 1 meg with the Fatter Agnus
  5982. 3) A big fast Hard Drive  
  5983. All three will make your programming environment much more comfortable as well as decrease your development time. 
  5984. ANIM Formats 
  5985. Before we explore the details of the ANIM routines, a little lecture about animation file formats will help you to understand the different ANIM functions. There are many ways to achieve a particular effect. Some are more memory efficient but slower, others are fast but conserve strained memory resources. Some animation effects might best be done with just the JForth PICTURE routines.   
  5986. There are two formats for storing the graphics information of an animation: an ANIMATION and an ANIMBRUSH. An ANIMATION is the more complicated of the two.  Its advantages are that it works well with a double buffered display and  it can be decompressed quickly.  An ANIMBRUSH has the advantage of ease of changing directions in playback at the cost of slightly slower decompression times. Understanding the structure of the two formats can help you take advantage of their strong points in your code.   
  5987. Both formats contain an initial ILBM graphic of the first frame of the animation.  The rest of the animation is stored in DELTA chunks which are data chunks that just specify the changes that must be made to a previous frame to generate a new frame. The DELTA chunks for the two formats are interpreted differently for the two types of files. 
  5988. An ANIMATION DELTA chunk contains the absolute value of new bytes in any changed area of the graphic. The DELTA chunks are setup so that each chunk modifies, not the current, but the previous frame of the animation. When double buffering is used the hidden previous frame is modified by a DELTA chunk to produce the next frame. Two extra DELTA chunks are added to the end of the animation sequence that allow regeneration of the first two frames of the animation so that looping effects can be performed. 
  5989. An ANIMBRUSH DELTA chunk contains the exclusive OR of the old and new bytes in any changed areas of the display.  The DELTA chunks act on the current frame to produce the next frame so that only one complete bitmap needs to be maintained.  The last DELTA chunk modifies the last frame to produce the first frame anew for looping.  Since the data is an exclusive OR of two consecutive frames, if the same delta is applied to the resulting frame, you get back the original.  This makes it easy to generate the frames in forward, backward, or ping pong order. 
  5990. Compiling the ANIM Toolbox
  5991. The ANIM and PICTURE toolboxes have so many routines that they will not fit in the normal JForth dictionary.  Luckily it is a simple matter to expand the dictionary space.  You can store this expanded Forth wherever you have room for it.  Let's assume you want to place it in a directory called TMP:.  You will need to substitute the name of your own directory. 
  5992. Enter in the SHELL: 
  5993. RUN COM:JFORTH
  5994. Enter in JFORTH: 
  5995. 200 #K !    \ allocate a 200K dictionary
  5996. SAVE-FORTH TMP:AnimForth
  5997. BYE
  5998. You now have a larger dictionary.  Enter in the SHELL: 
  5999. RUN TMP:AnimForth
  6000. Enter in JFORTH: 
  6001. INCLUDE JANIM:LOAD_ANIM
  6002. After that compiles, let's save it so we don't have to recompile each time. 
  6003. SAVE-FORTH TMP:AnimForth
  6004. From now on, you can just run that image and have everything ready for immediate use. 
  6005. Tutorial 1 - Displaying an ANIM File 
  6006. (Before proceeding with these tutorials, you should be familiar with the PICTURE IFF system described in chapter 21.) 
  6007. Before performing any JForth graphics operations, we must initialize the graphics system and open the GRAPHICS and INTUITION library. To do this, enter: 
  6008. GR.INIT
  6009. This tutorial assumes you have Deluxe Paint III as a source of an animation. If not use any ANIM-5 animation file that's available to you. Enter: 
  6010. CD DPAINT:ANIM
  6011. DIR
  6012. You should see a file called CRY.  If the above doesn't work, don't worry.  You can use any ANIM for this tutorial, assuming that it fits in your memory. 
  6013. Animations use a special structure to keep track of all the cels in the ANIM as well as other graphical information. This structure is an extension to the PICTURE structure. Let's declare a structure for our ANIM. Enter: 
  6014. ANIMATION CRYANIM
  6015. Now we can load the animation from disk.  This will use the IFF parser to scan the IFF file.  The deltas, which describe the differences between successive cels, will be loaded into memory.  If the load fails, it will return an error flag on the stack.  We print that to make sure the load worked.  In an animation application, you should check this flag and respond appropriately. Enter: 
  6016. CRYANIM ANIM.LOAD? CRY  .
  6017. Since this is the first ANIM loaded, it will open a screen of the proper size and display the first frame.  To get back to the WorkBench screen, hold down the <LEFT-AMIGA> key and hit the 'N' key. To get back to the image, hit <LEFT-AMIGA>+M. 
  6018. Now back in JForth, enter: 
  6019. ANIM_LOOP CRYANIM ANIM.PLAY
  6020. ANIM.PLAY will start displaying the  animation in a loop until you click in the top left corner on the hidden closebox or hit a key on the keyboard. 
  6021. This Animation played as fast as the ANIM.PLAY routine could generate the next frame. This may be too fast for your particular purpose. The defered word ANIM.DELAY is called within the playback loop after each new frame is displayed. A simple way to slow down the playback would use the Vertical Blank delay: 
  6022. : WAIT20  ( --- )
  6023.   20 WAIT.FRAMES
  6024. ;
  6025. ' WAIT20 is ANIM.DELAY
  6026. Note that the delay word must have a stack diagram that neither expects  nor leaves anything on the stack. 
  6027. To remove the animation from memory when finished. Enter: 
  6028. CRYANIM ANIM.FREE
  6029. Tutorial 2 - ANIM Control and Disk Based ANIMS 
  6030. Assume we have an animation called SPIN in the current directory. Let's do some explorations with it. First let's create an animation structure for it and load it into memory. Enter: 
  6031. ANIMATION MYSPIN      
  6032. MYSPIN ANIM.LOAD? SPIN   .
  6033. You should see the first frame appear.  Now  jump back to the JForth window using the keyboard combination <LEFT-AMIGA><N>. (Hold down the left amiga key, then press 'N'. You can get back to the Animation with <LEFT-AMIGA><M>.) Click in the JForth window and enter: 
  6034. MYSPIN ANIM.STATS 
  6035. You will see a list of information about the SPIN animation. The value displayed for CURRENT FRAME will be zero based for the first loop of the  animation and 1 based on subsequent loops. Enter: 
  6036. MYSPIN ANIM.DISPLAY.NEXT? .
  6037. You should see the next frame of the animation appear. If you have HISTORY ON you can step through the animation by pressing UP-ARROW RETURN combinations. Note that you will keep looping through the frames of the animation after you have passed the "last" fame. If garbage appears instead then the animation you are viewing does not have a two frame loop ending in the animation file.  Flip back to JForth and do ANIM.STATS at different points in the animation. You should note that the sequence of frame numbers change  between the first loop and the second. (Note that you can also use ANIM.VIEW.NEXT? which is faster but can have some surprising behavior.  See the references to PIC.VIEW for more explanation.) 
  6038. The ANIMATION structure maintains two pictures. One is displayed and the other is hidden.  You can see them by: 
  6039. MYSPIN ..@ an_hiding     PIC.DISPLAY
  6040. MYSPIN ..@ an_displaying PIC.DISPLAY ( restores the original)
  6041. Let's play the SPIN animation from disk. First free the memory version: 
  6042. MYSPIN ANIM.FREE
  6043. This also closes the screen. Enter: 
  6044. MYSPIN ANIM.DISK.LOAD? SPIN  .  ANIM_ONETIME MYSPIN ANIM.PLAY
  6045. MYSPIN ANIM.FREE
  6046. You will see the animation play through once and stop on the last frame. Depending on the speed of your disk drive and the complexity of the animation results may range from good to poor (from floppy drive). Loading and playing from disk might allow very long animations to be shown or at least previewed.
  6047. Tutorial 3 - ANIMBRUSHES 
  6048. AnimBrushes are like brushes in a paint program, except they have multiple frames or cels, like an Animation.  An example might be a bird flapping its wings.  For this next tutorial you will need a still picture and an AnimBrush.  You could use the ones that came with JForth or you could make your own.  Let's assume you now have a background picture that we will call BACKG and an AnimBrush brush that we will call BIRD. (It doesn't have to be a bird but we have to call it something!) It is best if they are made with the same pallette, otherwise the AnimBrush colors may look odd. 
  6049. Although AnimBrushes could be loaded into their own screen, they are more useful when drawn on top of another image.  Let's, therefore, load the background picture first so that it defines the screen. The filenames used are for the images on the JTools disk.  You may substitute your own files.  Enter: 
  6050. PICTURE BACKG      \ declare a picture structure
  6051. " jpics:mountains.pic" BACKG $PIC.LOAD? . \ load image
  6052. Now let's define the AnimBrush stucture and load an AnimBrush file: 
  6053. ANIMBRUSH BIRD
  6054. " jpics:bird.anbr" BIRD $ABR.LOAD?.
  6055. Since a picture was being displayed at the time of the load you saw no change in the display. If nothing was being displayed then a screen would open and display the first frame of the animbrush. You may want to drag the WorkBench screen down a bit so that you can see the graphics and the JForth window at the same time. 
  6056. An AnimBrush can be blitted onto the screen just like brushes, enter: 
  6057. 10 20 BIRD ABR.BLIT
  6058. The special thing about AnimBrushes is that you can advance to the next frame and blit that.  Enter: 
  6059. BIRD ABR.ADVANCE
  6060. 10 20 BIRD ABR.BLIT
  6061. If you don't want the full rectangle of the brush, you can blit transparently. Let's move to new x,y coordinates so we can see the difference. Enter: 
  6062. BIRD ABR.ADVANCE
  6063. 95 14 BIRD ABR.TRANS.BLIT    \ note .TRANS.
  6064. Use the <UP-ARROW> key to reenter the two previous commands several times. Notice that the new blits overlap the previous blits. Techniques to prevent this by saving the background and restoring are described in the PICTURE tutorial. The same techniques can be used with AnimBrushes. Actually, almost any PIC. call can be used with AnimBrushes including wipes and other effects. Don't however, use PIC.FREE or PIC.LOAD with AnimBrushes! 
  6065. Now let's define some words that will help us further explore AnimBrushes. Enter: 
  6066. : SHOW.BIRD ( -- , display current frame of bird )
  6067.     10 20 BIRD ABR.BLIT
  6068. ;
  6069. : NEXT.BIRD  ( -- , show next cel of Bird )
  6070.     BIRD ABR.ADVANCE
  6071.     SHOW.BIRD
  6072.     BIRD ABR.GET.FRAME . CR? \ print where we are now
  6073. ;
  6074. ABR.GET.FRAME returns the frame, or cel, of the AnimBrush currently ready to blit.  We can force an AnimBrush to a particular frame using ABR.GOTO.FRAME. Enter: 
  6075. 0 BIRD ABR.GOTO.FRAME  \ move to first frame
  6076. SHOW.BIRD   \ show it
  6077. NEXT.BIRD   \ show next frame
  6078. 3 BIRD ABR.GOTO.FRAME
  6079. SHOW.BIRD
  6080. If you tell ABR.GOTO.FRAME to a frame beyond the end of your brush, it will just print a message to that effect and do nothing. You can tell how many cels you have by reading it out of the AnimBrush structure. Enter: 
  6081. BIRD S@ ABR_CELS .  \ print total number of cels
  6082. Let's now define a word that will continuously advance the AnimBrush. Enter: 
  6083. : PLAY.BIRD ( -- )
  6084.     BEGIN
  6085.         NEXT.BIRD
  6086.         6 WAIT.FRAMES \ wait 6 video frames, 6/60 seconds
  6087.         ?TERMINAL
  6088.     UNTIL
  6089. ;
  6090. PLAY.BIRD
  6091. Notice that the bird is advancing and that the numbers go up to the highest frame then start over again at zero. Let's reverse the direction of play. Hit <RETURN> to stop PLAY.BIRD and enter: 
  6092. BIRD ABR.REVERSE
  6093. PLAY.BIRD
  6094. If you would like the brush to PINGPONG, or go both directions, enter: 
  6095. ABR_PINGPONG BIRD S! ABR_FLAGS
  6096. PLAY.BIRD
  6097. Notice the numbers go up to the maximum then back down to zero, etc. To get back to the normal mode, enter: 
  6098. ABR_LOOP BIRD S! ABR_FLAGS
  6099. PLAY.BIRD
  6100. When you're done using these images don't forget to enter: 
  6101. BIRD ABR.FREE
  6102. BACKG PIC.FREE
  6103. To further explore this toolbox, look in the directory, JANIM:TESTS. It contains test programs that can also serve as simple examples. By studying these files, you will see how to create animbrushes from two pictures using ABR.BUILD?. You can then append other pictures to the end using ABR.APPEND.CEL?.  You can also edit the internal structure of animbrushes using ABR.DUP.CEL? , ABR.DELETE.CEL? and ABR.REPLACE.CEL?. 
  6104. Animation Tips
  6105. If you need to edit an animation, you can convert it to an animbrush using ANIM>ANIMBRUSH?, edit it, then convert it back using ANIMBRUSH>ANIM?. 
  6106. In an application, you can bring the animation to the front using ScreenToFront().  The screen address is stored in the variable SIFF-SCREEN so enter: 
  6107. SIFF-SCREEN @ ScreenToFront()
  6108. ANIM Support Glossary
  6109. ANIM IFF tools
  6110. These words are used in reading ANIM-5 IFF files. 
  6111. $ANIM.LOAD? ( $filename animation  --- error? ) 
  6112. Load animation for playback.  The main load routine. IF an_flags set to ANIM_DISKMODE then a disk mode load will occur. 
  6113. $ANIM.DISK.LOAD? ( $filename animation  --- error? ) 
  6114. The ANIM_DISKMODE flag is set and $ANIM.LOAD is called. The animation will be kept on disk and read as it is played.  This is handy for very large ANIMs. 
  6115. $ANIM.PREP? ( $filename --- error? ) 
  6116. Setup of variables and animation filename previous to an $ANIM.SCAN? . 
  6117. $ANIM.SAVE?  ( $filename animation -- error? ) 
  6118. Saves the animation to the file. You cannot save a DISKMODE animation with this word. 
  6119. $ANIM.SCAN? ( $filename --- error? ) 
  6120. Scans the anim file for delta and anim-header chunks. 
  6121. ANIM.BLIT  ( x y animation -- )
  6122. Animations contain two pictures that are needed to reconstruct the images using double buffers.  This word will blit the currently picture to the destination RastPort.
  6123. ANIM.DISK.HANDLER ( size chkid -- ) 
  6124. Reads DLTA chunks and collects the FSEEK and size data in lists to be able to access the chunk from disk. 
  6125. ANIM.DISK.LOAD? ( animation <filename> -- error? ) 
  6126. For disk based loading with filename in the input stream. This cannot be used in a colon definition. Use $ANIM.DISK.LOAD? instead. 
  6127. ANIM.HANDLER ( size chkid -- ,  handles ANIM specific chunks ) 
  6128. Reads DLTA chunks and allocates memory for them. 
  6129. ANIM.LOAD? ( animation <filename> -- error? ) 
  6130. For memory mode loading with filename in the input stream. This cannot be used in a colon definition. Use $ANIM.LOAD? instead. 
  6131. ANIM.PARSER ( size chkid -- , recursively parse ANIM ) 
  6132. Used by $ANIM.SCAN to collect info about ANHD and DLTA chunks present in the file. Precollecting this data allows more efficient memory allocation for the ANIM file. 
  6133. ANIM.READ.ANHD? ( size --- error? ) 
  6134. Reads an Anim-Header chunk into ANIM-HEADER from current IFF file. Checks for correct size. 
  6135. ANIM.SAVE?  ( animation <filename> -- error? ) 
  6136. This cannot be used in a colon definition. Use $ANIM.SAVE? instead. 
  6137. Saves the animation to the filename from the input stream. 
  6138. ANIMATION Words
  6139. These are used to display ANIMATIONs.
  6140. ANIM.ADVANCE? ( animation -- error? , advance to next frame) 
  6141. Calls ANIM.APPLYDELTA or ANIM.APPLYDISKDELTA as needed to generate the next frame. The HIDDEN and DISPLAYING buffer pointers are then switched.  Will loop around at end. 
  6142. ANIM.APPLYDELTA ( anim -- ) 
  6143. Using the hidden pic buffer applies the current memory based delta. Then bumps the delta pointer looping it to 1 if at the last delta. Does not swap the hidden and displayed buffer pointers or cause the new data to be displayed. 
  6144. ANIM.APPLYDISKDELTA? ( anim -- error? ) 
  6145. Same as ANIM.APPLYDELTA but obtains the data from disk.
  6146. WARNING: to use this word you need to previously open the disk based file with ANIM.DISK.OPEN. At the present time only ONE disk based anim can be open. Since the IFF routines are used to read the data you also must not do an IFF read or write operation while the file is open. 
  6147. ANIM.CHECK ( animation -- , abort if bad ) 
  6148. Looks for the correct value in the an_key field. 
  6149. ANIM.DELAY ( --- ) 
  6150. A deferred word called by ANIM.PLAY between frames. It can be used to slow down the playback or add syncronization effects. 
  6151. ANIM.DISK.OPEN? ( animation -- error? ) 
  6152. Opens the original file read by the ANIM.DISK.LOAD routine for disk based animations. If you gave a directory relative filename at the original load, you must be in the same current directory to reopen it. 
  6153. ANIM.DISK.CLOSE ( --- ) 
  6154. Closes the file. 
  6155. ANIM.DISPLAY.NEXT? ( animation -- error? ) 
  6156. Calls ANIM.ADVANCE? to generate the next frame then displays it using PIC.DISPLAY.  This is slower then ANIM.VIEW.NEXT? but preserves the Intuition Screen order. 
  6157. ANIM.FREE ( animation -- , free all parts of animation ) 
  6158. Releases all the allocated memory for the animation and clears the animation struct. 
  6159. ANIM.GET.DEPTH ( animation -- depth ) 
  6160. Returns the number of bit planes in the animation. 
  6161. ANIM.LAST.FRAME? ( animation --- flag ) 
  6162. Returns a TRUE flag if at the last frame of an animation. This is valid ONLY IF the animation contains the typical two extra DELTA chunks for looping. Otherwise returns TRUE on the 3rd from last frame. Problem if the anim has less than 3 frames. 
  6163. ANIM.PLAY ( loopflag animation --- ) 
  6164. Loopflags are ANIM_LOOP (TRUE) which plays the animation in a loop, or ANIM_ONETIME (FALSE) which plays up to the "LAST" frame. 
  6165. ANIM.STATS ( animation --- ) 
  6166. Displays info about the current state of the animation. 
  6167. ANIM.VIEW.NEXT? ( animation -- error? ) 
  6168. Calls ANIM.ADVANCE? to generate the next frame then displays it using PIC.VIEW.  This is much faster then ANIM.DISPLAY.NEXT? but can cause some confusion because it overlays the Intuition Screen display using low level code.  See PIC.VIEW. 
  6169. ANIMATION ( <animname> --- ) 
  6170. Creates a structure in the dictionary for an animation. 
  6171. ANIMBRUSH Words 
  6172. Load and display AnimBrushes.
  6173. $ABR.LOAD? ( $filename animbrush  --- error? ) 
  6174. Since the first IFF load routine used opens a screen, you should load your backgroud picture first so that the display mode can be set. After loading the default direction is set to ABR_FORWARD and the mode flag is set to ABR_LOOP. See ABR.REVERSE. 
  6175. $ABR.SAVE?  ( $filename animation -- error? ) 
  6176. Saves the animbrush to the file. 
  6177. ABR.ADVANCE ( animbr -- ) 
  6178. Applies current DELTA to the animbrush then updates the delta pointer depending on the current state of the direction and mode flags. 
  6179. ABR.BLIT ( x y animbr --- ) 
  6180. Blits the animbrush into the current rastport then calls ABR.ADVANCE to generate the next frame. A simple PIC.BLIT will do as well but won't advance the frame. The PIC.BLIT call will work since the start of the animbrush structure is a PICTURE struct. 
  6181. ABR.CHECK ( animbr -- , abort if bad , used internally ) 
  6182. ABR.FREE ( animbr -- , free all parts of animbrush ) 
  6183. ABR.GET.FRAME ( animbr --- current-frame ) 
  6184. Returns the current frame number ( 0 1 2 .. N ) of the bitmap state of the animbrush. Uses the current direction to deduce the current frame. 
  6185. ABR.GOTO.FRAME ( frame animbr --- ) 
  6186. Cycles in the current direction until the asked for frame is generated. 
  6187. ABR.LAST.FRAME? ( animation --- flag ) 
  6188. Returns a TRUE flag if at the last frame of an animbrush. 
  6189. ABR.LOAD? ( animbrush <filename> -- error? ) 
  6190. Reads filename from input then calls $ABR.LOAD. This cannot be used in a colon definition. Use $ABR.LOAD instead. 
  6191. ABR.REVERSE ( animbr --- ) 
  6192. Reverses the direction of the animbrush. That is the order in which the frames are generated by ABR.ADVANCE is reversed. ABR.REVERSE does NOT change the current bitmap. Since we allow forward and backward modes we must deduce the correct DELTA to use if we want to change directions. 
  6193. ABR.SAVE?  ( animation <filename> -- error? ) 
  6194. Saves the animbrush to the file name from the input stream. 
  6195. ABR.STATS ( animbrush --- ) 
  6196. Displays info about the current state of the animbrush. 
  6197. ABR.TRANS.BLIT ( x y animbr --- ) 
  6198. The PIC.TRANS.BLIT word only casts the bitmap into its shadow on the first call. Since our bitmap is changing from frame to frame ABR.TRANS.BLIT recasts the shadow at each frame. 
  6199. ANIMBRUSH  ( <animbrname> --- ) 
  6200. Creates a structure in the dictionary for an animbrush. 
  6201. CONVERSION Words
  6202. Support for various conversion and animation editing code for EOR delta encoding used in Animbrushes.  A true error? flag can be returned if there is insufficient memory for the operation.   For examples of their use, see "JAnim:tests/test_conversion.f".
  6203. ABR.APPEND.CEL? ( picture animbr -- error? ) 
  6204. Appends a picture to the end of an AnimBrush. Must be same size as the animbrush. 
  6205. ABR.BUILD? ( pic0 pic1 animbr -- error? ) 
  6206. Builds a two frame animbrush from the two pictures. The width and height of the pictures should be set to the size of the entire bitmap of the pictures. You can use PIC.WHOLE to ensure this. The two pictures must be equal in size. The color map of pic0 is used in the generated animbrush. 
  6207. ABR.CUR.DELTA ( abr -- delta-address ) 
  6208. Returns the address of the current (next) delta 
  6209. ABR.DELETE.CEL?  ( cel# animbr -- error? ) 
  6210. Deletes given cel from animbrush.  An error can occur if memory cannot be allocated for the new deltas. 
  6211. ABR.DUP.CEL? ( cel# animbr -- error? , inserts a duplicate cel ) 
  6212. Adds a new cel to animbrush that is a duplicate of the given cel. 
  6213. ABR.MAKE.DELTA ( pic0 pic1 -- delta | 0 ) 
  6214. Using the two given pictures makes an EOR type delta which is used in AnimBrushes. If the Delta cannot be allocated, this will return zero. You must free the delta when you are done using FREEBLOCK unless you add it to an AnimBrush.  In that case it will get freed when you free the AnimBrush The pictures must be the same size. 
  6215. ABR.NORM ( animbr -- ) 
  6216. Changes direction to FORWARD and mode to LOOPING, saving previous state. 
  6217. ABR.REPLACE.CEL? ( picture cel# animbr -- error? ) 
  6218. Modifies the cel to be the given picture. Picture must be the same size as the animbrush. Calculates the needed changes  in the deltalist. 
  6219. ANIM.MAKE.DELTA ( pic0 pic1 -- delta | 0 ) 
  6220. Using the two given pictures makes an ABS type delta which is used in Animations. If the Delta cannot be allocated, this will return zero. You must free the delta when you are done using FREEBLOCK unless you add it to an Animation.  In that case it will get freed when you free the Animation.  The pictures must be the same size. 
  6221. ANIM>ANIMBRUSH.PARTIAL? ( first_cel# last_cel# anim animbr -- error? ) 
  6222. Convert part of an Animation to an AnimBrush. 
  6223. ANIM>ANIMBRUSH? ( anim animbr -- error? ) 
  6224. Constructs an AnimBrush from all of an initalized Animation. This calls ANIM>ANIMBRUSH.PARTIAL? with a first cel# of 1, and a last cel# of 1.  This will go through all cels and wrap around to the beginning. 
  6225. ANIMBRUSH>ANIM.PARTIAL? ( first_cel# last_cel# animbr anim -- error? ) 
  6226. Convert part of an AnimBrush to an Animation. 
  6227. ANIMBRUSH>ANIM? ( anim animbr -- error? ) 
  6228. Constructs an Anim from all of an initalized AnimBrush. This calls ANIMBRUSH>ANIM.PARTIAL? with a first cel# of 1, and a last cel# of 0.  This will go through all cels and wrap around to the beginning. 
  6229. ENCODECOL ( blk  ht -- ) 
  6230. Encodes a column in VSkip format in Delta-work @. 
  6231. EORplane ( ABSpl0 ABSpl1 ABSdeltabuff w h -- ) 
  6232. Calculates and rotates an EOR type deltaplane.
  6233. MAKE.ABSDELTA  ( pic0 pic1 -- ) 
  6234. Creates an absolute style delta for use in ANIMs. Delta stored at DELTA-WORK. Used in ANIMBRUSH>ANIM. 
  6235.  
  6236. LOW LEVEL support words 
  6237. These words are used internally by the Animation system. You would not normally call these directly. They are documented here in case you need to make internal modifications or to extend the system. 
  6238. ADD.YTABLE.USER  ( ytable -- ) 
  6239. Increment the YTable user counter. See FREE.YTABLE 
  6240. ALLOC.YTABLE ( byteoffset linesize -- ytable | 0 )
  6241. Creates or reuses a YTable. Fails if no memory available or no room is left in list. The constant MAX_Ytabs determines the memory reserved for the list. 
  6242. ALLOC.YTABLE.TRACKER ( -- tracker | 0 ) 
  6243. Called automatically by the first request for a YTABLE. Won't hurt anything if done again. A YTABLE is a multiplication table used by the ANIM and ABR routines to optimize the decoding of deltas. 
  6244. CountSames ( buff length -- SameCount ) 
  6245. Low-level word to scan a delta plane for same runs. 
  6246. CREATE.YTABLE ( byteoffset linesize  --- ytable | 0 ) 
  6247. Allocates and calculates a multiplication table for the decode routines. 
  6248. DECODE_VKPLANE (  inDELTA outBITPlane ytable --- ) 
  6249. ASM code to decode a bitplane of info from a DELTA chunk. This routine expects the DELTA to consist of the absolute byte values in vertical byte skip form. Used by ANIMATION files. 
  6250. DECODE_XORVKPLANE ( inDELTA outBITPlane ytable --- ) 
  6251. ASM code to decode a bitplane of info from a DELTA chunk. This routine expects the DELTA to consist of EOR byte values in vertical byte skip form. Used by ANIMBRUSH files. 
  6252. FINDOP  ( buffptr len --- cnt op ) 
  6253. Main low-level word for VSkip encoding of a rotated EOR encoded buffer. 
  6254. PUSHBYTE ( byte memblk -- ) 
  6255. Pushes byte to allocated memoryblock 
  6256. FIND.YTABLE ( byteoffset linesize --- ytable | 0 )
  6257. Checks if an appropriate YTable is available for shared use. If so returns its address, if not returns 0. 
  6258. FREE.YTABLE ( ytable --- ) 
  6259. Frees memory for a YTable if not marked by another user. Last free deallocates the ytable list as well. 
  6260. FREELIST? ( listaddr -- ) 
  6261. Listaddr is the relative address of an allocated memory block obtained by a ALLOCBLOCK call. This block contains addresses of a series of memblock addresss. FREELIST? parses the list and does a FREEBLOCK on each memblock in the list, then does a FREEBLOCK for the list. 
  6262. SCANFORZU ( dataaddr length -- Z U ) 
  6263. Low-level word to scan a delta plane for zero and unique runs. 
  6264.  
  6265. 22 -      Anims and Animbrushes
  6266.  
  6267.     Anims and Animbrushes    22 -  
  6268.  
  6269.  
  6270.  
  6271.  
  6272.  
  6273.  
  6274. Chapter 23
  6275. ARexx Support 
  6276. The JForth ARexx support was written by Mike Haas, Martin Kees and Phil Burk.  We at Delta Research would like to thank Martin for his generous contributions. 
  6277. Note: You must have ARexx installed in your system for these tools to be useful.  ARexx is a native component of AmigaDOS 2.0 or later.  If you are using AmigaDOS 1.3 or earlier, you must purchase ARexx and install it.
  6278. What is ARexx?
  6279. ARexx is a programming language that can communicate with other applications.  Using ARexx, for example, one could request data from a database application and send it to a spread sheet application.  To support this facility, an application must be "ARexx compatible" by being able to receive commands from ARexx and execute them.  A database program might have commands to search for, retrieve, and save data.  MicroFiche Filer is an example of a database program with an extensive ARexx command set.  A text editor might have ARexx commands corresponding to its editing command set.  The Textra editor supplied with JForth has an extensive ARexx command set, which can be used with JForth to provide an 'integrated programming environment' (see the 'Integrating Textra and JForth' section in this chapter for details).  AmigaVision, the multimedia presentation program, can control other programs using ARexx. ARexx can increase the power of a computer by combining the capabilities of various programs. Because of the wide acceptance of ARexx, Commodore includes it with Version 2.0 of AmigaDOS. 
  6280. If you are developing an application, it is highly recommended that you provide ARexx compatibility, if appropriate. The JForth ARexx Toolbox provides the basic tools needed to call ARexx.  It also provides some higher level tools for implementing a command parser, and for manipulating ARexx variables. 
  6281. ARexx was developed for the Amiga by William Hawes.  It is based on the REXX language described by M.F. Cowlishaw in The REXX Language: A Practical Approach to Programming (Prentice-Hall 1985) 
  6282. Description of Files
  6283. The JForth support for ARexx is in a directory with the logical name "JRX:". 
  6284. These files comprise the primary Arexx support files: 
  6285. ARexxCalls.f = JForth calls to ARexx library
  6286. ARexxTools.f = tools to simplify the use of ARexx
  6287. MakeArexxMod = Make ARexx module, used when JForth is built 
  6288. RXUnderKey.f = Install ARexx listener under KEY (eg. for Textra)
  6289. RexxClude.f  = Support for Textra to ARexx interface 
  6290. RexxVars.f   = Calls for manipulating Rexx variables RexxView.f   = An application that monitors ARexx messages for debugging 
  6291. There are a number of test programs supplied as examples of using ARexx from JForth. When the ".f" test files are compiled, they will print instructions to the screen.  The ".rexx" and ".srh" files are ARexx scripts. The test files are in JRX:TESTS and are: 
  6292. sample_rexx_host.f  = sample Rexx host application.  Use this as a model for your own applications.
  6293. drive.srh  = rexx script to drive above sample
  6294. macro1.srh  = rexx script callable as a macro from above sample 
  6295. Test_RXTools.f  = simple example of controlling JForth from ARexx 
  6296. ToJF.rexx  = sends commands to Test_RXTools.f 
  6297. vartestf.f  = JForth program for testing RexxVars.f
  6298. testrvi.rexx  = Rexx Script for testing RexxVars.f 
  6299. Low Level ARexx Support
  6300. ARexx structures and constants are defined in "include" files. These have been precompiled into a module called AREXXMOD. To access this module from your program, enter: 
  6301. GETMODULE AREXXMOD
  6302. JForth compatible calls to the ARexx library are also provided. These routines are documented in the ARexx manual. ARexx is somewhat unusual in that some of the routines return multiple values.  Special tools had to be added to the JForth CALL facility to support these. To load these words, enter: 
  6303. INCLUDE JRX:AREXXCALLS.F
  6304. To see the stack diagram of words in the library, use FILE?. For example: 
  6305. FILE?  STCTOKEN()
  6306. will show you the following definition: 
  6307. : StcToken()  ( string -- token scan length quote )
  6308.     call>abs RexxSysLib_lib StcToken  TuckA1 TuckA0 TuckD1
  6309. ;
  6310. ARexx Toolbox Tutorial
  6311. [Please familiarize yourself with the ARexx manual before beginning this tutorial.  ARexx must be installed for this to work.] 
  6312. To simplify the development of ARexx compatible programs, we have provided an optional toolbox.  This toolbox has routines for initializing the ARexx system, interpreting commands and argument strings, sending messages to ARexx, and cleaning up afterwards. To load this toolbox, enter: 
  6313. INCLUDE JRX:AREXXTOOLS.F
  6314. To communicate with ARexx, we need to open the RexxSysLib library, create a message port, and initialize a message.  When we open a message port, we have to give it a name that will serve as an "address" for ARexx messages.  If we have an application called "JAZZ", we can do all of the above with a single call. Enter: 
  6315. : JAZZ.INIT.RX  ( -- error? , setup ARexx )
  6316.     0" JAZZ" RX.INIT
  6317. ;
  6318. Note that we used 0" instead of just " because ARexx and AmigaDOS use NUL terminated strings.  A NUL terminated string is a string of ASCII characters ending with a zero. This is different than a Forth string that begins with a count byte equal to N, followed by N characters. When looking at stack diagrams, parameters like 0NAME and 0STRING are NUL terminated strings. Parameters like $NAME and $STRING are Forth style strings. See 0COUNT >DOS DOS0 and 0" in the Forth glossary for more information. 
  6319. The stack diagrams for the RX.xxx words can be found in the glossary in this chapter. 
  6320. We put the call to RX.INIT in a colon definition for two reasons. One is so that the 0NAME would be permanently compiled in the dictionary instead of being on the PAD.  Strings defined outside of a colon definition go on the PAD and are soon overwritten.  The second reason is because when you write applications, all of the code should be in colon definitions and not just called when the file compiles.  For the purposes of the rest of this tutorial, however, we will often just type things in directly because it is easier when experimenting. Now enter: 
  6321. JAZZ.INIT.RX  .
  6322. The number printed should be zero.  It could be equal to the constants ERR_INSUFFICIENT_MEMORY or RXERR_NO_LIBRARY if either of those errors occurred. Checking for RXERR_NO_LIBRARY is one way to determine whether ARexx is installed on a system. 
  6323. Now let's try sending a message through ARexx to our program. Make sure that you have a Amiga DOS Shell or CLI window open before executing the next command! Enter: 
  6324. RX.WAIT.MSG
  6325. Notice that JForth has not returned from this word.  It is waiting for a message from ARexx.  Now click in the Shell window and enter an ARexx command. Pay close attention to the single and double quotes. Enter in the Shell (NOT in JForth): 
  6326. RX ' address "JAZZ" "play song" '
  6327. Notice that JForth has now returned with 1 item on the stack which is the message from ARexx. Notice also that RX in the Amiga Shell window has not returned. RX is waiting for its message back so don't lose the message in JForth. 
  6328. What does the RX command mean?  When you enter an RX command in the shell, you can give as a parameter either an ARexx script filename or an ARexx command delimited by quotes.  We used the ADDRESS command to send the message "play song" to the address "JAZZ". Let's now look in JForth to see if we got it.  Enter: 
  6329. 0 OVER RX.ARG[] \ get address of 0th argument
  6330. @ IF>REL        \ fetch it, convert to relative address
  6331. 0COUNT TYPE     \ print it
  6332. ARexx messages have up to 16 arguments that can be referenced using RX.ARG[].  They generally contain the absolute address of an ARexxString so we must convert it to relative before using it. The message printed should have been "play song" from our RX command. 
  6333. Now we must reply to the message so that RX can continue. Enter: 
  6334. DUP .  \ see that our message is still there
  6335. RX.REPLY.MSG
  6336. Let's look at another way of getting messages. Enter: 
  6337. RX.GET.MSG DUP . \ should be zero
  6338. 0SP
  6339. Zero means that there were no messages for our program.  Let's send another message from the Shell. Enter in the Shell (NOT in JForth): 
  6340. RX ' address "JAZZ" "12345 howdy" '
  6341. Let's see if we can pick up that number in JForth. Enter in JForth: 
  6342. RX.GET.MSG DUP .         \ should be non-zero
  6343. 0 OVER RX.ARG[] @ IF>REL \ get 0string
  6344. RX.PARSE.NUM .S          \ extract number
  6345. You should now see four numbers on the stack.  The first is our message address, followed by 12,345 (!), followed by the address of the remainder of the string, and a -1 = TRUE. Let's take three of them off of the stack. 
  6346. . \ -1
  6347. 0COUNT TYPE \ howdy
  6348. .  \ 12,345
  6349. Now before we reply to the message, let's pretend we detected an error that we want to tell ARexx about.  The error could be due, for example, to a number out of range, an illegal command, or a song name that JAZZ doesn't know how to play. The numbers that you use are decided upon by you. Let's use 23 for now. To pass an error number back to ARexx, enter: 
  6350. 23  RX-RESULT1 !
  6351. RX.REPLY.MSG
  6352. RX should print that the command returned '23'. 
  6353. An application that supports ARexx commands is called an ARexx host. Most ARexx hosts will need to implement a command set that can be used by other programs. Each command will have a name, a particular set of arguments, and an associated Forth function. We have simplified this process for you.  Suppose that we have a very small command set: one word that prints dollar signs, and another that prints a string and a number. These are trivial routines.  Your application can have many powerful routines but these two will serve as examples. 
  6354. First let's define our command functions. 
  6355. : DOLLARS  ( N -- )
  6356.     0 DO ASCII $ EMIT LOOP CR
  6357. ;
  6358. : TYPE.  ( ADDR COUNT N -- )
  6359.     . CR
  6360.     TYPE CR
  6361. ;
  6362. Test them by entering: 
  6363. 5 DOLLARS
  6364. " World Peace" count 123 TYPE.
  6365. Now lets define a word that, sets up the command interpreter. 
  6366. : JAZZ.SETUP  ( -- )
  6367.     2 RX.ALLOC.CTABLE  \ just two commands
  6368.     IF
  6369.         " DOLLARS" " N" 'C DOLLARS RX.ADD.COMMAND
  6370.         " TYPEDOT" " SN" 'C TYPE. RX.ADD.COMMAND
  6371.     ELSE
  6372.         ." Couldn't allocate table!" cr
  6373.     THEN
  6374. ;
  6375.  
  6376. JAZZ.SETUP
  6377. The stack diagram for RX.ADD.COMMAND is: 
  6378. RX.ADD.COMMAND ( $name $format cfa -- )
  6379. The format is a string of 'N's and 'S's.  For each N, an number will be parsed and passed to your function.  For each S, an ADDR and COUNT of a string will be parsed and passed.  The stack diagram of your functions must correspond to the format that you give. 
  6380. There are several ways to use the command table. See RX.EXEC.MSG below. For a simple test we can use RX.SLAVE.SAFE.  This will terminate when we touch the keyboard which is handy for testing. Enter: 
  6381. RX.SLAVE.SAFE
  6382. Now enter in the Shell (NOT in JForth): 
  6383. RX  ' address "JAZZ" "DOLLARS 10" '
  6384. RX  ' address "JAZZ" "TYPEDOT hello 123" '
  6385. RX  ' address "JAZZ" "DOLLARS 25" '
  6386. Notice the messages in the JForth window. Now hit <RETURN> in JForth to stop RX.SLAVE.SAFE. When we are done with our command table, we should free it by entering: 
  6387. RX.FREE.CTABLE
  6388. Now let's finish by entering: 
  6389. RX.TERM
  6390. Instead of entering ARexx commands directly from the Shell, we could use scripts.  Study the test programs in JRX:TESTS for more examples.  Pay special attention to JRX:TESTS/SAMPLE_REXX_HOST.F. 
  6391. ARexx Toolbox Glossary 
  6392. These words are compiled from JRX:ARexxTools.f 
  6393. RX-SAVE-MSG  ( -- addr , saved from RX.GET.MSG )
  6394. If your program aborts before getting a chance to call RX.REPLY.MSG, you can get the last message from this variable and reply to it.  The use RX.FLUSH.MSG repeatedly until the Rexx program finishes.
  6395. RX.ADD.COMMAND ( $name $format cfa -- ) 
  6396. Add a command to the command table.  You must call RX.ALLOC.CTABLE first. The format is a string of 'N's and 'S's.  For each N, an number will be parsed and passed to your function.  For each S, an ADDR and COUNT of a string will be parsed and passed.  The stack diagram of your functions must correspond to the format that you give. 
  6397. : RX.ALLOC.CTABLE ( n -- table | 0 )
  6398. Allocate table for commands.   Call RX.FREE.CTABLE when finished using table. Returns zero if not enough memory. 
  6399. RX.ARG[]  ( n rexxmsg -- arg-addr , index into argument array ) 
  6400. Calculate address of an argument in a rexx message.  If the argument is a string it will be stored as an absolute address so use IF>REL after you fetch it and IF>ABS before storing a string. 
  6401. RX.EXEC.LINE ( 0arg -- error? ) 
  6402. Looks up command in table, parses arguments based on format, and passes as parameters to a Forth function specified by RX.ADD.COMMAND. Error? will be zero, RXERR_ILLEGAL_COMMAND, RXERR_ILLEGAL_PARAMETER or the contents of RX-ERROR as set by your code.
  6403. If the word whose CFA you pass in RX.ADD.COMMAND has the wrong stack diagram and leaves something on the stack or eats too much from the stack, you will get an error message and an abort.  Please then fix the word for that command.  This is considered a serious programming error thus we abort instead of returning a flag.
  6404. RX.EXEC.MSG ( rexxmsg -- ) 
  6405. Pass argument 0 to RX.EXEC.LINE then sets RX-RESULT1 to ERROR?. 
  6406. RX.FIND.COMMAND ( addr cnt -- index true | false ) 
  6407. Look up command in table. 
  6408. RX.FLUSH.MESSAGES ( -- #msgs ) 
  6409. Reply to all messages not yet processed. Sets RX-RESULT1 = 10. 
  6410. RX.FREE.CTABLE ( -- , free allocated table ) 
  6411. Free table allocated by RX.ALLOC.CTABLE. 
  6412. RX.GET.MSG ( -- rexxmsg | 0 , if any are ready ) 
  6413. Be sure to reply using RX.REPLY.MSG when done with message. 
  6414. RX.INIT  ( 0hostname -- error? ) 
  6415. Open RXSysLib library, create message port, and create a RexxMsg for use if needed. 
  6416. RX.JFORTH.INIT ( -- error? , initialize port as "JFORTH" ) 
  6417. RX.KILL.SCRIPT ( rexxmsg -- , send CTRL-C to rexx script ) 
  6418. RX.PARSE.NUM ( 0string -- num 0scan true | false ) 
  6419. RX.PARSE.STRING ( $format 0string -- ...params... 0left true | false ) 
  6420. Params will contain N for each 'N' in $format, and ADDR COUNT for each 'S'. If an error is encountered, a false is returned. 
  6421. RX.PUT.ACTION ( action -- , set in rx-message-ptr ) 
  6422. Set action field in RX-MSG-PTR.  See ARexx manual for an explanation. 
  6423. RX.PUT.MSG  ( 0arg 0portname -- error? ) 
  6424. Sends the argument to the named port.  Uses NUL terminated strings. Converts the argument to an official ARexx ArgString and calls SafePutToPort(). RX.PUT.MSG then waits for and processes messages using RX.EXEC.MSG until the original packet is returned. 
  6425. RX.PUT.REXX ( 0arg -- error? ) 
  6426. Send message to resident process REXX   Calls RX.PUT.MSG with a portname of 0" REXX". 
  6427. RX.PUT.TEXTRA ( 0arg -- error? )
  6428. Calls RX.PUT.MSG with a portname of 0" TEXTRA". The RXCOMM, RXFF_RESULT, and RXFF_STRING bits are first set in the action field then restored to just RXCOMM. 
  6429. RX.REPLY.MSG ( rexxmsg -- ) 
  6430. Replies to message.  Passes RX-RESULT1 (integer) and RX-RESULT2 (argstring) if they are set and the sender requested a reply by setting the RXFF_RESULT flag. 
  6431. RX.SLAVE ( -- , process ARexx commands until RX-QUIT on ) 
  6432. Wait for messages, execute them using RX.EXEC.MSG, then reply to them.  This continues until the variable RX-QUIT is set to TRUE.  You must provide a quit command to do that. 
  6433. RX.SLAVE.SAFE ( -- ) 
  6434. Like RX.SLAVE but also quits if you hit a key. 
  6435. RX.TERM  ( -- , terminate if initialized ) 
  6436. RX.WAIT.MSG ( -- rexxmsg ) 
  6437. Be sure to reply using RX.REPLY.MSG when done with message. As an alternative to waiting for the ARexx message, you could AND several Signals together and use Wait().  This would allow you to get IDCMP events while waiting for ARexx events.
  6438. SafePutToPort() ( msg 0portname -- ok? ) 
  6439. Finds a port with the given name then sends it a message. Uses Disable() and Enable() calls. 
  6440. Integrating Textra and JForth 
  6441. Textra is a text editor written in JForth by Mike Haas. It is optimized for program development as opposed to word processing. Textra is provided with JForth and can be found in the JTX: directory. Textra can be freely redistributed. 
  6442. Mike has added an ARexx interface to Textra that allows you to manipulate text from other programs. Textra also provides the ability to compile programs directly from the Textra window without going to disk. If an error is encountered during compilation, the offending line is highlighted. 
  6443. To prepare the Textra/ARexx interface, you will need to copy the scripts to the REXX: directory. Enter in the shell: 
  6444. COPY JTX:SCRIPTS REXX: ALL CLONE
  6445. Now run Textra, select "AREXX..." from the Utilities menu. Click in one of the long text gadgets and enter "jcompile". We recommend the gadget associated with <F10>.  Then click on the <SAVE> button.  Finally, click the <CANCEL> button to close the requester.
  6446. To compile the Textra Interface into JForth, enter in JForth: 
  6447. INCLUDE JRX:RexxClude.f
  6448. To activate the interface, enter: 
  6449. RX.INSTALL
  6450. JForth will now be ready for any ARexx message sent to the port named "JFORTH". 
  6451. Note: Do not INCLUDE directly from Textra when you are writing programs that use the RX.xxx words.  They will fight over the ARexx port and both will lose.  Specifically, do not call RX.INIT when RX.INSTALL is active.  Instead, write the file to disk and call the normal INCLUDE.
  6452. To test this interface, open a file using textra and enter a few lines of code.  Put a deliberate error in one of the lines.  The hit the <F10> function key. 
  6453. JForth will begin to compile the contents of the Textra window. When it reaches the bug, it will highlight it in Textra. You can now fix the bug and hit <F10> again. 
  6454. You can use SAVE-FORTH to save an image with this code already compiled.  When you run this image RX.INSTALL will be called automatically by AUTO.INIT. 
  6455. Warning: Do NOT select other windows or edit text while JForth is compiling from the window. 
  6456. I recommend that you read the documents in JTX:DOCS. The file RexxCommand.doc contains a description of the commands that Textra supports.  As long as we have Textra up and RX.INSTALL active let's have some fun. 
  6457. Arrange your windows so that you can see the shell window, the JForth window and a Textra window all at once. In the Textra window, you should have a file with at least 20-30 lines for this experiment. 
  6458. Note: Textra commands require a '@' before the command when sent from JForth.  This is to distinguish commands from invocations of a script.
  6459. Lets try repositioning the Textra cursor. Enter in JForth: 
  6460. 0" @GOTOXY 10 5" RX.PUT.TEXTRA .
  6461. Did you notice the cursor jump in Textra.  Enter these other commands and watch the cursor move. 
  6462. 0" @LEFT 3" RX.PUT.TEXTRA .
  6463. Now lets try selecting a line. 
  6464. 0" @SELECTLINE 8" RX.PUT.TEXTRA .
  6465. Now let's try retrieving the text that is currently selected in Textra.  Select a different line if it is empty in your file. Enter: 
  6466. : GETIT  ( -- , get and type )
  6467.     0" @get select text" rx.put.textra . cr
  6468.     rx-result2 @ 0count type cr
  6469. ;
  6470. GETIT
  6471. The text is left at HERE which can be overwritten so be sure to copy it somewhere else if you want to keep it. 
  6472. Now would be a good time to try out some of the commands described in the JTX:Docs/RexxCommand.doc file.  You may also want to read some of the scripts in JTX:Scripts.
  6473. ARexx Variables Interface 
  6474. The REXX Variables Interface (RVI) is a set of functions to allow an ARexx host to manipulate a macro program's symbol table.  Using these functions the host can retrieve values for existing variables and install new values. There is no limit (except for available memory) to the number of variables that can be created, so the variables interface is a very convenient way to pass information to a macro program. 
  6475. [Martin Kees created this code by disassembling REXXVARS.O which is a linkable object file supplied with ARexx. RVI was developed by William Hawes.] 
  6476. The RVI functions can be called whenever the ARexx host holds a pending command message from an ARexx program.  While the command message is outstanding, the macro program is waiting for the reply and the program's symbol table is in a consistent state.  All calls to the interface functions must be completed before the message is replied. 
  6477. In a typical application, a macro program issues a command to the host to perform some specific action, and may pass the name of a stem variable as an argument.  The host performs the command and fills in the appropriate variables before replying to the message.  When the macro program resumes operation, it can check the values of the variables set by the host. 
  6478. Here is an outline of that transaction: 
  6479. 1) JForth host calls ARexx macro (optional).
  6480. 2) ARexx macro sends command to JForth host.
  6481. 3) JForth host can read or write macros variables using RVI.
  6482. 4) JForth host replies to command.
  6483. 5) ARexx macro can use new values in variables. (optional)
  6484. Variable Names 
  6485. Variable names are specified by a pointer to a null-terminated string and must follow the REXX language symbol conventions.  Alphabetic characters must be in UPPERCASE.  The variable name is treated as a literal string, and no substitution for compound symbols is performed. 
  6486. The host application should document the variables affected by each command so that the macro programmer knows where to find the information, and to avoid accidental conflicts in variable names.  If a large number of values must be passed, the host should define them as compound variables and let the macro program pass the stem name as an argument. 
  6487. The RVI Glossary 
  6488. To use the RVI functions, include the file "JRX:RexxVars.f". It is not necessary to define the ARexx library base (RexxSysBase), as the ARexx library is opened on the fly when required. 
  6489. CheckRexxMsg ( rexxmsg -- ok? ) 
  6490. This function verifies that the message pointer is a valid RexxMsg and that it came from an ARexx macro program.  The validation test is more stringent than that performed by the ARexx library function IsRexx(). The latter verifies that the message is tagged as a RexxMsg structure, but not that it necessarily came from an ARexx macro program.  Each macro program installs a pointer to its global data structure in the command message, and this pointer is necessary to gain access to the symbol table. 
  6491. The return from the function will be non-zero (TRUE) if the message is valid, and 0 (FALSE) otherwise. 
  6492. GetRexxVar ( rexxmsg 0variablename -- 0value error? ) 
  6493. This function retrieves the current value for the specified variable name. It first validates the message using CheckRexxMsg() and then, if the message pointer is valid, retrieves the value string and passes it in the supplied return pointer.  The return pointer is actually an argstring (an offset pointer to a RexxArg structure), but can be treated as a pointer to a null-terminated string.  The value must not be disturbed by the host. 
  6494. The function return will be zero if the value was successfully retrieved and non-zero otherwise.  An error code of 10 indicates an invalid message. 
  6495. Here is an example of getting and displaying the value of a variable named PRICE. 
  6496. MyRexxMsg 0" PRICE" GetRexxVar 0=
  6497. IF  ." Price = " 0count type cr
  6498. ELSE drop ." AN error occured getting PRICE" cr
  6499. THEN
  6500.  
  6501. SetRexxVar ( rexxmsg 0variablename addrval length -- error? ) 
  6502. This function installs a value in the specified variable.  It validates the message pointer using CheckRexxMsg() and then installs the value, creating a symbol table entry if required.  The value is supplied as a pointer to a data area along with the total length; the data may contain arbitrary values and need not be null-terminated. 
  6503. The function return will be zero if the call was successful and non-zero otherwise.  The possible error codes are given in the table below. 
  6504. Error Code  Reason for Failure
  6505. 3        Insufficient storage
  6506. 9        String too long
  6507. 10    Invalid message
  6508. Here is an example of setting a variable named PRICE to 1234. 
  6509. MyRexxMsg 0" PRICE" 1234 n>text SetRexxVar
  6510. IF ." Could not set PRICE!" cr
  6511. THEN
  6512. Note that the value returned by GetRexxVar() is an argstring (pointer), and the value passed to SetRexxVar() is just a pointer to a data area. 
  6513. RVI Code Examples and Test Program 
  6514. A sample JForth program and an ARexx script to exercise the RVI functions are included. They are: 
  6515. JRX:Tests/VarTest.f
  6516. JRX:Tests/TestRVI.rexx
  6517. VarTest opens a public port named "VarTest" and waits for messages to arrive from ARexx.  Each message is validated with a call to CheckRexMsg(), after which the value for A.1 and A.2 is retrieved using GetRexxVar(). The program then installs the value "A-OK" in the variable STATUS and replies the message.  VarTest exits when it receives a "CLOSE" command. The ARexx program TestRVI.rexx will demonstrate the VarTest host. 
  6518. Note how the variable values are affected by the procedure calls in ARexx. In the first call from TestMem, A.1 will be NULL. Then it will be set to "Local to TestMem" for the next call. Then it reverts to its original value when we return from the procedure TestMem. This is because PROCEDURE in ARexx creates a new symbol table. A.2 keeps its value because it is EXPOSEd. 
  6519. Here is the procedure for running this test program: 
  6520. In JForth:
  6521. INCLUDE JRX:RexxVars.f  \ takes a while to assemble
  6522. INCLUDE JRX:tests/VarTest.f
  6523. VARTEST
  6524. In Amiga Shell:
  6525. RX JRX:Tests/TestRVI
  6526. RexxView
  6527. RexxView is a CLI utility that monitors the REXX port. Information is listed to a file describing each message received by REXX.  JForth source code is in file jrx:RexxView.f.  RexxView is designed to be cloned.
  6528. Usage: 
  6529. rexxview  outfile
  6530. For example: 
  6531. rexxview con:0/0/640/100/rv
  6532. (or)
  6533. rexxview PRT:
  6534. Rexxview is terminated by sending the string "closerexxview" to the REXX port.  To do this enter in the CLI: 
  6535. rx closerexxview
  6536.  
  6537. 23 -      ARexx Support
  6538.  
  6539.     ARexx Support    23 -  
  6540.  
  6541.  
  6542.  
  6543.  
  6544.  
  6545.  
  6546. Chapter 24
  6547. Miscellaneous Amiga Support     
  6548. What is supported and why?   
  6549. You may be wondering how we decided which Amiga functions we would define JForth words for and which not.  Our primary goal is to provide the necessary tools for accessing any Amiga functions. The CALL system and the Structure referencing tools provide this.  These are theoretically all you need to access the Amiga libraries.  This is why some functions are not directly supported.  As for why some function are supported, there are four main possible reasons.  The first reason might be that a function is so important that almost everyone will want it.  The second is that the function might be a little tricky to implement so we will save you the pain, like the polygon or IFF code.  The third reason is if it is a function normally present in 'C' but not part of the Amiga libraries, eg. CreateStdIO().  The final reason would be if we needed a function to write one of the demos or applications and then included it in a support file for all to use.   
  6550. The routines that follow all pass addresses as relative addresses.  Words that end in a '()' suffix map are simply calls to the Amiga library functions.  Most of these calls are described in detail in the ROM Kernal Manual.   
  6551. File JU:GRAPH_SUPPORT
  6552. These routines support various Graphics and Intuition Library calls.
  6553. ALLOC.BITMAP ( bdepth bwidth bheight -- bitmap | false )  
  6554. Allocate a BitMap structure with bitplanes based on the input.  Calls InitBitMap().  This BitMap must eventually be freed using FREE.BITMAP.   
  6555. ALLOC.RASTPORT ( -- rastport | 0 , allocate and initialize)  
  6556. ALLOC.SHADOW ( bdepth bwidth bheight -- bitmap | false )  
  6557. Allocates a special kind of bitmap that has only one plane allocated for each plane position.  This is used for building shadow masks for transparent Blit operations.  Must be freed using FREE.SHADOW.   
  6558. ALLOCRASTER() ( x y -- address )  
  6559. BITMAP>WH ( bitmap -- width height , extract information )  
  6560. BltBitMapRastPort() ( bitmap x y rp x y w h minterm -- )  
  6561. BltClear() ( memblock bytecount flags -- )  
  6562. BMPLANE[] ( index bitmap -- &plane-ptr )  
  6563. This points to the position in the BitMap that holds the address of the plane.  It is not the plane address itself.  Do a @ >REL to get the plane address.Used when allocating and assigning planes both.   
  6564. CLEAR.BITMAP ( bitmap -- , set planes to zero )  
  6565. Clear all the bit planes in a BitMap to zero using BltClear().   
  6566. CLEAR.BITPLANE ( plane# bitmap -- , clear plane of bitmap ) 
  6567. ClipBlit() ( src_rp x y dest_rp x y w h minterm -- )  
  6568. CLOSEFONT() ( font -- )  
  6569. COPY.PLANES ( src_bm dest_bm -- , copy planes into other bitmap )  
  6570. This copies the pointers to the planes of one BitMap to another BitMap. This can be useful for double buffering.  Be careful you don't free these planes twice!  
  6571. CTABLE>RGB  ( index ctable -- r g b , extract colors )  
  6572. Extract Red, Green, and Blue values from a colortable.  A colortable is packed 0RGB in 16 bits.   
  6573. FREE.BITMAP ( bmap -- , free planes then the Bitmap )  
  6574. FREE.SHADOW ( bmap -- , free plane then the bitmap )  
  6575. For freeing Shadow mask allocated by ALLOC.SHADOW.   
  6576. FREE.VIEW ( view -- , free CPR lists and deallocate ) 
  6577. FreeCprList()  ( CPRList -- ) 
  6578. FREERASTER() ( address x y -- )  
  6579. FreeVPortCopLists()  ( viewport -- ) 
  6580. INITBITMAP() ( bitmap depth width height -- )  
  6581. INITRASTPORT() ( RastPort -- )  
  6582. INITTMPRAS() ( tmpras buffer size -- )  
  6583. INITVIEW() ( view -- )  
  6584. INITVPORT() ( viewport -- )  
  6585. LOADRGB4()  ( viewport colortable n -- , load color palette )  
  6586. LOADVIEW()  ( view -- )  
  6587. MAKEVPORT()  ( view viewport -- )  
  6588. MRGCOP()  ( view -- )  
  6589. PACK.RGB  ( r g b -- ctable-entry )  
  6590. Pack the 4 bit Red, Green, and Blue values into 16 bits organized as 0RGB.   
  6591. RASSIZE() ( height width -- size_in_bytes )  
  6592. REMAKE.SCREEN ( screen -- , rebuild Amiga display system )  
  6593. RGB>CTABLE  ( r g b index ctable -- , store colors )  
  6594. Opposite of CTABLE>RGB.  Uses PACK.RGB  
  6595. ROTATE.PLANES ( bitmap -- , rotate planes for effect )  
  6596. An interesting color shifting effect can be obtained if you rotate the order of the plane pointers in a Bitmap.  This is very fast since you are only changing pointers.  You must rotate as many times as there are planes to get back to normal.   
  6597. SCALE.COLOR ( color scalar -- color' , 0-16 scale )  
  6598. Scale a 4 bit color value where the scale ranges from 0 to 16 where 16 is equivalent to 1.0.   
  6599. 7 16 scale.color  ( get 7 back ) 
  6600. 7 8  scale.color  ( get 3 back ) 
  6601. SCALE.CTABLE ( ctable1 ctable2 many scalar -- , scale c1 into c2)  
  6602. Copy a colortable into another by unpacking the RGB values, scaling them, then repacking them back into the new colortable.  Useful for fading in and out a picture.   
  6603. SCALE.RGB ( r g b scalar -- r' g' b' )  
  6604. SetRast()  ( rastport pen -- )  
  6605. SWAP.PLANES  ( bmap1 bmap2 -- , swap planes between bitmaps )  
  6606. SWITCH.SCREEN ( rastport screen -- , switch double buffer )  
  6607. If the RastPort is used for drawing and the screen for displaying, you can create a double buffered image by drawing, then calling SWITCH.SCREEN.   
  6608. WAIT.FRAMES ( N -- , wait for N blanking intervals )  
  6609. Loop on WaitTOF()  
  6610. WaitTOF() ( -- , wait till next vertical blank )  
  6611. Font Support      
  6612. See the demo JD:DEMO_FONT for an example of the use of these routines.   
  6613. GET.FONT ( 0name ysize -- font | NULL )  
  6614. Fills a text attribute structure with the necessary data and gets the disk based font.  This font can then be passed to GR.FONT! for use with the graphics toolkit.   
  6615. OPENDISKFONT() ( textattr -- font | NULL )  
  6616. OPENFONT() ( textattr -- font | NULL)  
  6617. SETFONT() ( rp font -- )  
  6618. File JU:GADGET_SUPPORT
  6619. The Amiga Gadget system provides an flexible way to control your programs. We have provided a set of routines for initializing the common Gadget structures to typical values.  You can then modify the values to suit your particular application.  See the demo JU:DEMO_GADGET for an example of their use.   
  6620. BOOLEAN.SETUP ( x y width height gadget -- )  
  6621. BORDER.SETUP ( width height border -- )  
  6622. BOX.SETUP ( width height addr -- , set 5 points for box )  
  6623. Used when creating a simple Border.   
  6624. CHECKBOX.SETUP ( x y width height gadget -- )  
  6625. INTGADGET.SETUP ( x y width height gadget -- )  
  6626. ITEXT.SETUP ( text0 intuitext -- , Set defaults. )  
  6627. MENUBUTTON.SETUP ( x y width height gadget -- )  
  6628. PROPGADGET.SETUP ( x y width height gadget -- )  
  6629. PROPINFO.SETUP ( hpot vpot hbody vbody propinfo -- )  
  6630. REFRESHGADGETS() ( gadgets ptr req -- )  
  6631. STRINGGADGET.SETUP ( x y width height gadget -- )  
  6632. STRINGINFO.SETUP ( buffer maxchars stringinfo -- )  
  6633. File JU:POLYGON for Area Fill   
  6634. To draw polygons you must first set up a temporary RastPort for creating a mask.  GR.AREA.INIT will create one based on the current RastPort whose absolute address is in GR-CURRPORT.  Then you can start a polygon by calling GR.AREA.MOVE followed by some number of calls to GR.AREA.DRAW then finally calling GR.AREA.END to draw the polygon.  When you are all done drawing all your polygons, please call GR.AREA.TERM to deallocate the temporary RastPort.  The system is set up with a limit of 100 points per polygon.  Change the source code if you need more.   
  6635. GR.AREA.INIT  ( -- , setup Temporary RastPort for polygons )  
  6636. GR.AREA.TERM  ( -- , deallocate temporary RastPort )  
  6637. GR.AREADRAW ( x y -- )  
  6638. GR.AREAEND ( -- )  
  6639. GR.AREAMOVE ( x y -- )  
  6640. GR.TRIANGLE ( x1 y1 x2 y2 x3 y3 -- )  
  6641. INITAREA() ( areainfo areabuffer count -- )  
  6642. File JU:SCREEN_SUPPORT      
  6643. The file JD:DEMO_HAM is a good example of these calls.  Please see the Intuition manual for a detailed description of these calls.   
  6644. BITMAP>SCREEN ( bitmap viewmode -- screen | NULL )
  6645. Opens a screen that uses the given bitmap as its CUSTOMBITMAP. 
  6646. CLOSESCREEN() ( screen -- )  
  6647. MAKESCREEN() ( screen -- , similar to MakeVport )  
  6648. MOVESCREEN() ( screen deltax deltay -- )  
  6649. A positive deltay will move the screen down.  Deltax is ignored.   
  6650. NEWSCREEN.SETUP ( NewScreen -- , Set default values )  
  6651. You can call this routine first then override the default values by setting them to your own.   
  6652. OPENSCREEN() ( NewScreen -- screen )  
  6653. REMAKEDISPLAY() ( -- , remake screens and COPR list )  
  6654. RETHINKDISPLAY() ( -- , reconstruct COPR list ): SCREEN>VIEW ( ascreen -- aview | NULL)
  6655. Moves screen to front then allocates a view based on the current display.  This view can be used with LoadView() to create double buffered displays.  Returns NULL (0) if the view could not be allocated.  Free the view using FREE.VIEW 
  6656. SCREEN>BACKWINDOW ( screen -- window | NULL ) 
  6657. Creates a BACKDROP window to fit a screen.  Sets the FLAGS and IDCMPFLAGS to the values in S>B_FLAGS and S>B_IDCMP_FLAGS. The default values are shown below. 
  6658. BACKDROP BORDERLESS | WINDOWCLOSE | REPORTMOUSE |
  6659. -> S>B_FLAGS
  6660.  
  6661. CLOSEWINDOW MOUSEBUTTONS |
  6662. VANILLAKEY | MENUPICK | GADGETUP | GADGETDOWN |
  6663. -> S>B_IDCMPFLAGS
  6664. SCREENTOBACK() ( screen -- , push to back )  
  6665. SCREENTOFRONT() ( screen -- , bring to front )  
  6666. SHOWTITLE() ( screen flag -- , SHow title bar or not.)  
  6667. Exec Library Support
  6668. These words support most of the calls in the Exec Library.  They can be found in the file JU:EXEC_SUPPORT.  All addresses are passed as JForth relative addresses.  Please see the ROM Kernal documentation for a description of these calls.   
  6669. ADDPORT() ( port -- )  
  6670. ALLOCSIGNAL() ( requested_signal# -- allocated_signal# )  
  6671. CHECKIO()  ( ioreqblk -- ioreqblk | 0 )  
  6672. CLOSEDEVICE() ( IORequest -- )  
  6673. DOIO() ( ioreqblk -- error , Do I/O )  
  6674. FINDPORT() ( 0$portname -- task )  
  6675. The portname is passed as a NUL terminated string which must be generated using 0" inside of a colon definition.   
  6676. FINDTASK() ( 0$taskname -- task )  
  6677. FREESIGNAL() ( signal# -- , Free previously allocated signal. )  
  6678. GETMSG() ( port -- message , Get message. )  
  6679. OPENDEVICE() ( 0$devicename unit# IORequest flags -- error )  
  6680. PUTMSG() ( port message -- , Put message. )  
  6681. REMPORT() ( port -- )  
  6682. ReplyMsg() ( message -- )  
  6683. SENDIO()  ( ioreqblk -- error )  
  6684. WAITIO()  ( ioreqblk -- error )  
  6685. WAITPORT() ( port -- message )  
  6686. Other Exec words - CreatePort() AbortIO() etc.  
  6687. The following words are commonly used but are not part of the Exec Library.  They are traditionally supplied as 'C' macros or are listed as 'C' source code in varous texts.  They have been converted to JForth code for your convenience.  You should always check the return value to make sure it is non-zero.  Unless otherwise specified, these routines can be found in JU:EXEC_SUPPORT.   
  6688. ABORTIO()  ( IOReqBlock -- result , abort an IO request )  
  6689. This is a special call directly off of a Device structure.  It returns a result but it is meaningless so you can drop it.  We found out about this when it was too late to change it.  This is defined in JU:DEVICE-CALLS. The above is also true of BeginIO().   
  6690. BEGINIO()  ( IOReqBlock -- result , start an IO request )  
  6691. See ABORTIO() definition.   
  6692. CREATEEXTIO() ( ioreplyport size -- ioreq | 0 )  
  6693. Allocate an extended IO Request Block that will use an existing IOReplyPort.   
  6694. CREATEPORT()  ( 0$name priority -- msgport | 0 )  
  6695. Allocate and add a new port to the system.   
  6696. CREATESTDIO() ( ioreplyport -- ioreq | 0 )  
  6697. DELETEEXTIO() ( ioext size -- )  
  6698. DELETEPORT() ( port -- , Delete message port )  
  6699. DELETESTDIO() ( ioreplyport -- )  
  6700. PORT.SETUP ( 0$name priority signal msgport -- , Set values.)  
  6701. Amiga Linked List Tools    
  6702. These routines can be found in the file JU:EXEC_LISTS.   They are Forth routines based on 'C' macros.  They are handy for examining Amiga system lists, or for creating your own lists.
  6703. DUMP.LIST ( list -- , dump nodes of list )  
  6704. DUMP.NODE  ( node -- , dump contents )  
  6705. FORBID() ( -- , forbid other tasks )  
  6706. If you are looking at system lists, you should forbid other tasks from changing them.  Call PERMIT() when done.   
  6707. LIST.ADDTAIL() ( list node -- , add node to end of list)  
  6708. LIST.FIRST() ( list -- first_node , get first node in list )  
  6709. LIST.IFEMPTY() ( list -- flag , true if empty )  
  6710. NEWLIST() ( list -- , Initialize list header )  
  6711. Set the pointers in a list header to point to itself.  This signifies an empty list.   
  6712. NODE.AFTER  ( node1 node0 -- , connect node1 after node0)  
  6713. NODE.INIT  ( type priority 0name node -- , initialize node )  
  6714. NODE.SUCC() ( node -- succeeding_node )  
  6715. PERMIT() ( -- , permit other tasks after FORBID() )  
  6716. ANSI Text and Cursor Control   
  6717. These commands allow the control of text and the cursor in a console window.  They send special control characters to the current output which are interpreted by the console device.  These commands are used extensively by the Command Line History system.  See also the file JU:COLORDUMP for more examples.  Please see the ROM Kernal Manual for more information.   
  6718. Note: The ANSI referred to here is the ANSI standard for terminal control characters, not the upcoming ANSI Forth standard.  ANSI stands for American National Standards Institute.  They standardize everything from languages to lightbulb sockets.
  6719. .DECIMAL  ( n -- , output decimal number without spaces )  
  6720. This is used to generate formatted ANSI commands.   
  6721. >STYLE  ( n -- , select graphic rendition )  
  6722. This is used by ITALICS and other ANSI words to select a style.   
  6723. ANSI.1C ( char -- , send CSI and one char )  
  6724. ANSI.BACKWARDS ( N -- , move cursor backwards )  
  6725. ANSI.DELETE ( N -- , delete character under cursor )  
  6726. ANSI.DOWN ( N -- , move cursor down )  
  6727. ANSI.ERASE.EOL ( -- , erase to end of line )  
  6728. ANSI.FORWARDS ( N -- , move cursor forwards   
  6729. ANSI.INSERT ( N -- , insert character )  
  6730. ANSI.NC ( N char -- , send a number and a character sequence )  
  6731. This is used to build special custom ANSI commands.   
  6732. ANSI.PARSE.SKR  ( -- key-code, get packed key sequence)  
  6733. If KEY returns a 155 decimal character, call this to parse the remaining characters.  It will eat keys and return a FKEY index equal to the following.  You can then use this in a CASE statement.  Remember that if history is on it will eat these special keys so your program will never see them.  Call HISTORY.OFF if you want to handle these characters yourself.   
  6734. 0 = error 
  6735. 1 = function key 1, 11 = shift 1, 
  6736. 2 = function key 2, 12 = shift 2, etc.  
  6737. 21 = cursor-up, 22 = cursor-down, 
  6738. 23 = cursor-right, 24 = cursor-left, 
  6739. 25 = shift-cursor-up, 26,27,28 (shifted v < >) 
  6740. 29 = help 
  6741. ANSI.UP ( N -- , move cursor up )  
  6742. B:0 B:1 B:2 B:3 ( -- , set text background color, see F:0 )  
  6743. BOLD       ( -- , make characters bold )  
  6744. F:0 F:1 F:2 F:3 ( -- , set text foreground color )  
  6745. These words will change the text color.  If history is interfering with this color, enter:  
  6746. HIGHLIGHT-INPUT OFF 
  6747. F:3  ( for fun ) 
  6748. B:2 
  6749. GOTOXY   ( x y -- , move text cursor to column x, row y )  
  6750. INVERSE    ( -- , style 7 )  
  6751. ITALIC     ( -- , style 3 )  
  6752. PLAIN      ( -- , style 0 )  
  6753. UNDERSCORE ( -- , style 4 )  
  6754. Amiga DOS 2.0 Support 
  6755. The ".j" include files were translated from Commodores AmigaDOS 2.0 ".h" files.  The conversion from 'C' to Forth was done using H2J which is in JA:H2J.F 
  6756. JForth makes the full field of AmigaDOS 2.0 features available to the programmer.  It is the programmer who must ensure that AmigaDOS functions and capabilities are not invoked under earlier versions of the operating system.
  6757. CHECK 2.0FEATURES? BEFORE CALLING AMIGADOS 2.0-SPECIFIC FEATURES AND FUNCTIONS!
  6758. Identifying the Workbench Version
  6759. 2.0FEATURES?  ( -- flag )
  6760. Returns a TRUE flag if running under AmigaDOS 2.0 or later.  The programmer should ensure his program is operating under 2.0 before using its services.  
  6761. JU:ASL_SUPPORT
  6762. ASL - the Application Support Library 
  6763. ASL is a new library provided in Amiga DOS 2.0. It provides facilities like file and font requesters.  We urge programmers to use these requesters in their applications because they provide the user with a familiar interface. One problem, however, is that if the user is running AmigaDOS 1.3, these cannot be used.  We suggest that you either require AmigaDOS 2.0 OR you should use the requester in JREQ:FileRequester.f when running under AmigaDOS 1.3. 
  6764. Here are some direct calls to the ASL library.  You must call ASL? before calling these routines. 
  6765. AllocASLRequest() ( type ptags -- request )
  6766. AllocFileRequest() ( -- request )
  6767. ASLRequest() ( request ptags -- result )
  6768. FreeASLRequest() ( request -- )
  6769. RequestFile() ( request -- result )
  6770. ASL Forth Utilities
  6771. We have provided some words that use the ASL library as a convenience and as examples.  These require AmigaDOS V2.0 or higher.
  6772. ASL.FILENAME>PAD ( file-request -- , copy full name to pad ) 
  6773. This can be called after using the File Requester.  It will concatenate the directory names and file names into a useable path name. The result will be left on the PAD.  It is used internally by ASL.REQUEST.FILE 
  6774. ASL.REQUEST.FILE ( 0prompt -- $name true | false ) 
  6775. Open the file requester with the given prompt.  If the user selects a file, return its name and a true.  If the user cancels the operation, return false.  The filename will be left on the pad.   See also the file requesters in JARP: and JREQ:.
  6776. : TEST.ASL ( -- )
  6777.     0" Select a file." ASL.REQUEST.FILE
  6778.     IF  COUNT TYPE CR
  6779.     THEN
  6780. ;
  6781. ASL.REQUEST.FONT ( 0prompt -- font true | false ) 
  6782. Open the font requester with the given prompt.  If the user selects a font, it opens it and returns a font pointer and a true.  If the user cancels the operation, return false. This routine opens the diskfont library and calls OpenDiskFont(). When you are done with the font, you should pass it to CloseDiskFont(). You can use this font by calling Intuition's SetFont().  See also GR.FONT! in JU:AMIGA_GRAPH. 
  6783. Tag Lists
  6784. TagLists are a new data structure in AmigaDOS 2.0. They are used to passed multiple attributes to a routine. The attribute identifier and a value are passed as pairs in a "list" that is terminated with a NUL. These routines simplify the creation and use of TagLists.   Taglist support is in JU:TAGLIST.
  6785. TAGLIST{  ( taglist -- ) 
  6786. Start the definition of a taglists. You must decide where to put the taglist.  You can put it in TAG-PAD, or in a memory area that you allocate.
  6787. }TAGLIST ( -- taglist ) 
  6788. Finish the definition of a taglist. This returns the address you passed to TAGLIST{ as a convenience.
  6789. TAG-PAD ( -- addr )
  6790. A place to put a taglist.  The maximum number of tags it will hold is 16. Do NOT exceed 16 tags.  If you need more tags, put them on the normal PAD or allocate memory.  This is used by ASL.REQUEST.FILE.
  6791. TAG, ( value -- , add to current taglist ) 
  6792. This is used by +TAG to add a single value to a taglist. 
  6793. +TAG ( attr value -- ) 
  6794. Add an attribute/value pair to a taglist. 
  6795. +TAG.ABS ( attr rel-addr -- ) 
  6796. Addresses in a taglist must be in absolute form for the Amiga. Use this word when adding addresses to a taglist.  If will convert non-zero values to absolute using IF>ABS. 
  6797. TAGLIST.DUMP ( taglist -- , dump taglist maximum 100 long) 
  6798. Dumps a taglist and shows each value as a number and as an address. 
  6799. Here is an example of using these words to create and display a taglist.  This taglist uses some of the tags for OpenWindowTagList(). 
  6800. INCLUDE? TAGLIST{  JU:TAGLIST
  6801. : MAKE.TAGLIST ( -- taglist )
  6802.     PAD       \ arbitrarily put it on PAD
  6803.     TAGLIST{  \ begin definition
  6804.         WA_HEIGHT  200  +TAG  \ set window height
  6805. \ now specify a custom screen ADDRESS
  6806.         WA_CUSTOM_SCREEN MY-SCREEN @ +TAG.ABS
  6807.     }TAGLIST
  6808.     dup taglist.dump
  6809. ;
  6810. 24-     Miscellaneous Amiga Support
  6811.  
  6812.     Miscellaneous Amiga Support    24- 
  6813.  
  6814.  
  6815.  
  6816.  
  6817.  
  6818.  
  6819. Key to Glossary     
  6820. This glossary contains descriptions of the most common JForth words.  To find words related to a specific function, eg. graphics or assembly, please look in the reference section.   
  6821. The words are organized in ASCII alphabetical order.  Many Forth words start with punctuation.  You can find out the alphabetical order for punctuation by looking at the bottom of the page in the glossary.   
  6822. Each Forth word description has a common format.  The first line of the description has the name of the word followed by a stack diagram.  The pronunciation of the word sometimes follows.   
  6823. Following the description of the word will often be an example, indented and in upper case.   
  6824. If the word is not in the normal JForth image, the file where it can be found will be given.   
  6825. Any related words will then be listed at the end of the description. Please also see the appendix on words related by function as well.   
  6826. Understanding Stack Diagrams     
  6827. Stack diagrams tell you what parameters are passed to a Forth word and what is returned.  The input and the output is separated by several dashes. Look at the stack diagram for + as an example.   
  6828. + ( a b -- a+b , add two numbers together ) 
  6829. This means that + takes two numbers, A and B, as input.  It leaves A+B as output.  The text after the comma is a comment.  The rightmost item is on the top of the stack so B is on top in this example.   
  6830. String Parameters      
  6831. There are a number of ways to pass a string in JForth.   
  6832. Parameters that start with a $ are Forth "counted strings".  The parameter will be the address of a count byte that will be followed in memory by that number of characters.  The Forth string "FROG", for example, will be stored in memory as:  
  6833. " FROG" 5 DUMP  ( reveals 04 46 52 4F 47 ) 
  6834. The first byte is the count byte.  The 46, 52, 4F, 47 are the ascii characters F R O and G.   
  6835. Forth also supports NUL terminated strings like 'C'.  Here, the address of the first character is passed.  The string continues until a zero is encountered.   
  6836. 0" FROG" 5 DUMP ( reveals 46 52 4F 47 00 ) 
  6837. These strings parameters are referred to with a zero in the name, eg. 0string.   
  6838. Forth strings can also be passed as an address and a count.   
  6839. Please examine the stack diagrams for COUNT and 0COUNT as examples.   
  6840. COUNT   ( $string -- addr count ) 
  6841. 0COUNT  ( 0string -- addr count ) 
  6842. Here are examples of the use of each.   
  6843. " FROG" COUNT TYPE 
  6844. 0" FROG" 0COUNT TYPE 
  6845. Strings can also be passed on the input line.  Consider the Forth word FOPEN which expects a filename to follow.  FOPEN opens a filename of the given name and returns a file-pointer which can be used to read the file. Here is an example of a call to FOPEN .   
  6846. FOPEN RAM:MYFILE 
  6847. Strings that are passed on the input line are enclosed in angle brackets in stack diagrams.  The stack diagram for FOPEN would, therefore, be:  
  6848. FOPEN   ( <filename> -- file-pointer | false ) 
  6849. The vertical bar and the FALSE means that if the file cannot be opened, a FALSE will be returned as an error indicator.   
  6850. Please keep in mind that some words may have an action but may not have any stack activity. The word CR, for example has a stack diagram of:  
  6851. CR ( -- , emit carriage return ) 
  6852. Return Stack      
  6853. There is also a Return Stack in Forth.  Words that affect the Return Stack will have a Return Stack Diagram.  These will be marked with a --R--.  Here is an example.   
  6854. >R   ( n -- , --R-- n , move N to the return stack ) 
  6855. Summary       
  6856. In summary, here is a description of the common parameters you will see:  
  6857. a b     = some values 
  6858. addr    = address of some memory location 
  6859. flag    = TRUE (-1) or FALSE (0) 
  6860. char    = ASCII character 
  6861. count   = number of things, usually bytes 
  6862. d       = double precision integer, 64 bit 
  6863. n       = single precision integer, 32 bit 
  6864. pad     = address of PAD , a scratch area 
  6865. u       = unsigned integer 
  6866. var-addr = address of a variable 
  6867. $addr   = counted string address 
  6868. $string = counted string address 
  6869. 0string = NUL terminated string address 
  6870. <text>  = text follows word 
  6871. <name>  = name of a Forth word 
  6872. <filename>      = name of a file 
  6873. |       = OR , denotes alternate parameters 
  6874. GL -      Key to Glossary
  6875.  
  6876.     Key to Glossary    GL -  
  6877.  
  6878.  
  6879.  
  6880. !   ( n addr -- )   "store"         
  6881. addr = even address 
  6882. Store 32 bit value N at even address ADDR.  This is the primary word for storing data in memory. Variables and other JForth data structures will always be word-aligned, ie. have an even address.  Code which may conceivably store 32-bit values to odd addresses should use ODD! .  The address is assumed to be a JForth relative address, not a 68000 absolute address.  
  6883. \ create and set a variable to '234' 
  6884. VARIABLE VAR1 
  6885. 234 VAR1 ! 
  6886. Related Words: >REL >ABS   ODDD!   ODD!   ODDW!  CMOVE FILL ODDW@  D!   W! C!   +!   @  C@   W@  ..@  ..! TRAPS  
  6887. !CSP   ( -- )   "store C S P"            
  6888. Stores the current parameter stack address in the user variable CSP.  Used with ?CSP to see if parameter stack is balanced and there were no compilation errors. Used to check stack depth between : and ;  
  6889. Definition:    :  !CSP ( -- )  SP@   CSP  !  ;  
  6890. Related Words: CSP  ?CSP  
  6891. "   ( <string> -- $addr )   "quote" 
  6892. Returns the address of quote delimited string.  The string will be stored as a count byte followed by the text.  Note that a space is required after the first quote.  If encountered while COMPILING, quote compiles the string into the dictionary, returning that address when executed.  If encountered while INTERPRETING, quote places the count at PAD, and the string at PAD+1, returning the PAD address.  Be aware that the PAD is used by many Forth words so strings generated when INTERPRETING are considered temporary.    
  6893. " Hello" COUNT TYPE 
  6894. Related Words: EMIT COUNT TYPE 0"  
  6895. #   ( d1 -- d2 ) 
  6896. "sharp" ( fig '83 )   "number" ( '79 )    
  6897. Used to convert numbers to a character string.  Divide D1 by current BASE, leaving remainder as D2.  Convert quotient to ASCII character, place character at address in HLD (below PAD), decrement HLD.   
  6898. : PHONE#  ( N -- , Print N as phone number) 
  6899.     S->D <# # # # #  ASCII - HOLD  #S #> 
  6900.     ( -- addr count ) TYPE SPACE ;  
  6901. Related Words: #S  <#  #>  HOLD PAD HLD COMMAS NO-COMMAS SIGN  
  6902. #>   ( d1 -- text_addr count ) 
  6903. Drop D1, terminating numeric output conversion, leaving address and count of the string.   
  6904. Standards:  '79, '83, FIG.   
  6905. : UD.  ( d1 -- , print an unsigned double number) 
  6906.     <#  #S  #>  TYPE ; 
  6907. #DIGITS   ( N -- #characters )   "number digits" 
  6908. Calculates how many characters are needed to display a number N, including commas if enabled.   
  6909. Related Words: N>TEXT  # NO-COMMAS COMMAS  
  6910. #K   ( -- addr )   "number k" 
  6911. Variable used by SAVE-FORTH to determine the size of a JForth image file. To increase the size of your dictionary, set this variable, do a SAVE-FORTH, then run the resultant image.   
  6912. \ Increase dictionary size by 20K 
  6913. 20 #K +! 
  6914. SAVE-FORTH MyImage 
  6915. Related Words: MAP SAVE-FORTH #U  
  6916. #RELOCS   ( -- addr )   "number relocs" 
  6917. A user-variable, containing the number of long absolute relocations that have been compiled. Internal.   
  6918. Related Words: PUSHRELOC  .IMAGE  MAP    
  6919. #S   ( ud -- 0 0 )   "number s" 
  6920. #S  converts the unsigned double value on the stack into an ASCII character string in memory. String location starts one byte below PAD and works down.  Produces only enough digits to represent the number. No leading zeros.  Always produces at least one digit which may be zero.  See # and #> .   
  6921. Related Words: <# # #> SIGN  HOLD  HLD  PAD #S  
  6922. #TIB   ( -- addr )   "number t i b" 
  6923. A user-variable containing the TOTAL number of characters in the TIB (terminal input buffer).   
  6924. : DUMP.TIB    TIB #TIB @   TYPE ; 
  6925. Related Words: TIB  'TIB  >IN  QUERY  
  6926. #U   ( -- addr )   "number u" 
  6927. #U is a variable that contains the number of allowable user variables.  If you run out of user variables, increase #U and do a SAVE-FORTH. Works like #K .   
  6928. Warning: once you make #U larger, you can't make it smaller. You must  go to an earlier Forth to get smaller user area.   
  6929. #VOCS   ( -- addr )   "number vocs" 
  6930. A user-variable, containing the current number of vocabularies defined in the dictionary.   
  6931. JForth allows a maximum of 32 vocabularies, two of which are defined in the minimum development system. #VOCS helps you to keep track of what vocabularies are available and what words  can be used.   
  6932. Related Words: #CHARS  
  6933. $   ( <hex-number> -- N )   "dollar" 
  6934. $ is used to force the interpretation of the next word in the input stream as a hexadecimal number, regardless of the current BASE.  $ is an IMMEDIATE word and, if found within a colon definition, will also compile the value into the dictionary as a LITERAL.   
  6935. decimal 256   $ 80 -   .  ( prints 128 ) 
  6936. Related Words: HEX DECIMAL  
  6937. $"      string quote  See " 
  6938. $,  string comma 
  6939. ( char -- )   ( <text> --in-- )   ( --inline-- <text> )  
  6940. Takes text from the input stream, delimited by char, compiles this text into the next available dictionary location.   
  6941. $, is a primitive used by the string literal words.  It performs the actual job of installing the text into the dictionary.   
  6942. $, is usually only called from higher-level words, such as " .   
  6943. $-   ( $1 $2 -- flag )   "string minus" 
  6944. Compare two strings alphabetically, return:  
  6945. flag = 0  if strings equal, 
  6946. flag = +1 if $1 greater than $2, 
  6947. flag = -1 if $2 greater than $1.  
  6948. Related Words: $= COMPARE  
  6949. $=   ( $1 $2 -- flag )   "string equals" 
  6950. $= performs a case-sensitive compare between 2 strings and returns true if equal, else false.
  6951. For case-INsensitive string matches, see MATCH? and TEXT=? .
  6952. Related Words: $- COMPARE MATCH? TEXT=?
  6953. $>0     ( $string -- ) "string to zero" 
  6954. Convert a normal Forth string, with a count byte, to a 'C' type NUL terminated string.  The conversion is done in place by shifting the characters down by one and placing a NUL, zero byte, at the end.  NUL terminated strings are used when passing strings to the Amiga libraries.   
  6955. Related Words: 0COUNT >DOS  
  6956. $APPEND   ( addr count dest-string -- )   "string append" 
  6957. This word is used to append text to the string at destination-string address.   
  6958. The count at address destination-string will be updated to reflect the increased string size.   
  6959. It is the responsibility of the calling program to insure that sufficient space exists above  address destination-string  to accommodate the increased string size.   
  6960. $DOLINES   ( $filename -- ) 
  6961. This is equivalent to DOLINES except it takes a filename on the stack. See DOLINES  
  6962. $DOS   ( $doscommand -- )   "string dos" 
  6963. Execute a string as a DOS command.   
  6964. : PWD ( -- , Print working directory. ) 
  6965.     " cd" $DOS ; 
  6966. $FOPEN  ( $filename -- file-pointer ) "string f open" 
  6967. Opens the file whose name is on the stack.  $filename is the address of a count byte.  A zero is returned if the file could not be opened.   
  6968. See FOPEN, 0FOPEN and chapter on File I/O.   
  6969. : OPENTEMP  ( -- file-pointer ) 
  6970.     " ram:temp" $FOPEN DUP 0= 
  6971.     WARNING" RAM:TEMP could not be opened!" ; 
  6972. $LOGTO   ( $filename -- ) 
  6973. Log all output to the file whose name is on the stack.  See LOGTO  
  6974. $MOVE   ( $addr-source addr-dest -- )   "string move" 
  6975. $MOVE moves a complete string, including the count byte.   
  6976. VARIABLE MYSTR 256 ALLOT 
  6977. " A text string" MYSTR $MOVE   ( move string to MYSTR ) 
  6978. $SIZE   ( $addr -- true-size )   "string size" 
  6979. $SIZE takes a string count-byte address and returns the number of bytes in the string plus the count byte plus any padding required to word-align the end.  Use COUNT if you want the actual number of characters in the string, without count-byte and padding.   
  6980. $TYPE   ( $addr -- )   "string type" 
  6981. $TYPE is a shorthand for COUNT TYPE.  It takes a string count-byte address and types out that string.   
  6982. '   ( <word> -- cfa )   "tick" 
  6983.  
  6984. All words in the dictionary have a body containing executable 68000 code. This word returns that address for any entry in the CONTEXT vocabulary.   
  6985. If executed within a colon definition. this IMMEDIATE word will locate the cfa of the next word as usual, then compile it as an address literal (ALITERAL) to be pushed to the stack at run-time.   
  6986. \ Use ' for indirect execution.  
  6987. : FOO ." Hello world!" CR ; 
  6988. ' FOO   EXECUTE   ( does FOO ) 
  6989. '>BODY   ( cfa -- pfa )   "tick to body" 
  6990. See >BODY  
  6991. '>NAME   ( cfa -- nfa )   "tick to name" 
  6992. See >NAME  
  6993. 'TIB   ( -- addr )   "tick T I B" 
  6994. This is a user-variable containing the JForth relative address of that users TIB area.  The value of this user-variable is placed on the stack by TIB .   
  6995. 'WORD   ( -- $addr )   "tick word" 
  6996. 'WORD is a DEFERred word that returns the address that WORD will use to PLACE its output.   
  6997. 'WORD usually is set to execute HERE.   
  6998. (   ( <text> -- )     "left  parenthesis" 
  6999. Text between parentheses is considered to be a comment in Forth.  The word ( will eat text until the closing ) .   
  7000. The opening ( must be followed by a space.  The comment is terminated with the next ) character, or end-of-line.  Note that a comment may NOT span more than one line. 
  7001. ( for humans only , put anything you want inside )   
  7002. Related Words: \ .IF                 
  7003. ($")   "parenthesis string quote" 
  7004. Compile time: ( -- )  ( <string> --in-- ) ( --inline-- <string> )  
  7005. Run time: ( -- $addr )  
  7006. ($") is used in inline string words like " $" etc...  ($") is compiled before using $, to place a string inline.  At run time, ($") will place the inline address of the string on the stack, and skip over the inline string to continue executing the code after it.   
  7007. : $\ COMPILE ($") ASCII \ $,  ; IMMEDIATE  
  7008. : FOO $\ A string with " in it!\ $TYPE ; 
  7009. Related Words: $" 0" (($")) "   
  7010. (($"))   "double parenthesis string quote" 
  7011. ( -- $addr )    ( $addr ip --R-- ip )  
  7012. (($")) is used in inline string words like (?ABORT") .  (($")) is used within words that must parse inline strings.  It is almost the same as ($") but it is used at 1 level of calling lower. See the STRINGS and STRING+ files for examples.   
  7013. : (?ABORT")  (($"))  SWAP  
  7014.     IF   CR $TYPE QUIT 
  7015.     THEN  DROP ; 
  7016. : ABORT"  COMPILE (?ABORT") ASCII "   $,  ; IMMEDIATE 
  7017. ((CREATE))   ( -- )   "paren paren create" 
  7018. This word creates a dictionary header out of a valid JForth string residing at HERE.  The dictionary pointer DP is left pointing to the code-field-address cfa , with the name-field-address being left SMUDGEd.   
  7019. ((CREATE)) is a primitive used by all defining words .   
  7020. (+LOOP)     "paren plus loop"  
  7021. ( inc -- )    ( n1 n2 --LOOP-STACK-- n1 n2+inc )  
  7022. n2 = index approaching overflow 
  7023. n1 = correction value to recreate index for I 
  7024. inc = increment amount 
  7025. (+LOOP) is the run time action compiled by +LOOP .  Used with DO .   
  7026. (+LOOP) adds inc to n2.  If n2 overflows, the LOOP is satisfied, and execution continues once the loop indices have been dropped from the LOOP-STACK.  If n2 does NOT overflow, return to the address immediately following the corresponding DO code.   
  7027. Related Words: LOOP DO -LOOP +LOOP -DO LOOP-BACK  LOOP-FORWARD REPEAT DO_FLAG
  7028. (-LOOP)      "paren minus loop" 
  7029. ( inc -- )   ( n1 n2 --LOOP STACK-- n1 n2-inc )  
  7030. n2  = index approaching overflow 
  7031. n1  = correction value to recreate index for I 
  7032. inc = increment amount 
  7033. (-LOOP) is compiled by -LOOP . Used with DO .   
  7034. (-LOOP) subtracts inc from n2.  If n2 overflows, the LOOP is satisfied, and execution continues once the loop indices have been dropped from the LOOP-STACK.  If n2 does NOT overflow, return to the address immediately following the corresponding DO code.   
  7035. Related Words: LOOP DO -LOOP +LOOP -DO LOOP-BACK  LOOP-FORWARD REPEAT DO_FLAG
  7036. (.")         "paren dot quote"    
  7037. ( -- )  ( $addr --R-- addr )  
  7038. $addr = string address 
  7039. addr  =  address of next word to be interpreted 
  7040. This word is a run time string-handler, used to print the string immediately following it's own compiled location.  It also modifies the program counter to jump around the string.  It is compiled by ." to output the string when executed.   
  7041. (.)   ( n -- )   "paren dot" 
  7042. The number primitive executed for signed integer output in the current BASE, usually executed by . (dot).   
  7043. Definition:   : (.)   ( n -- )  S->D D.  ;  
  7044. (;)   ( -- )  "paren semi-colon" 
  7045. This word is a primitive used in closing any colon definition.  It does the following.   
  7046. 1. Verify stack integrity (via ?CSP).
  7047. 2. Compiles the RTS opcode (necessary at the end of all
  7048.    JForth definitions).
  7049. 3  Reveals the name-field to FIND, so that it may accessed.
  7050. 4. Terminates COMPILE mode, returning to INTERPRET mode.
  7051. (?DO)   ( limit index -- )   "paren question do" 
  7052. (?DO) is compiled by DO .   
  7053. At run time, (?DO) check to see if the difference between the
  7054. index and limit is a positive, non-zero value.
  7055. - If so, it converts the index and limit to LOOP parameters, 
  7056.   and pushes them on the LOOP-STACK.
  7057. - IF not, it drops both parameters, and jumps past the
  7058.   corresponding LOOP word.
  7059. (?LEAVE)   ( flag -- )   "paren question leave" 
  7060. (?LEAVE) is compiled by ?LEAVE .  Used for conditionally leaving a DO LOOP.   
  7061. (?LEAVE), at run time, will check a flag on the stack...
  7062. - If non-zero, it will drop the loop indices and jump past
  7063.   the corresponding LOOP word.
  7064. - If zero, operation continues.
  7065. (?TERMINAL)  ( -- true-if-key-flag ) "paren question terminal"    
  7066. (?TERMINAL)  is the run time code for ?TERMINAL . ?TERMINAL is a  deferred word normally set to (?TERMINAL) .  In the '83 standard this is referred to as (?KEY) .   
  7067. (ABORT)   ( -- )   "paren abort" 
  7068. This is the default word which the DEFERred word ABORT executes.  It  calls QUIT.   
  7069. (CFA,)   ( cfa -- )   "paren c f a comma" 
  7070. Compile the appropriate code necessary to execute the word whose CFA is on the stack.   
  7071. Once the compiler has decided to compile a reference to an existing word, this is the primitive which figures out the particular manner of compilation which will be used, ie. INLINE, BSR, short or long JSR.   
  7072. This is the default contents of the DEFERred word CFA, and is the real workhorse of the compile process.   
  7073. (CFA,) determines whether the referenced CFA is of the INLINE type.  If so, a copy of the body of that definition is moved to the current DP, and its length is ALLOTed from the dictionary.   
  7074. If (CFA,) determines the word is of the BOTH variety, it checks the value of MAX-INLINE, and if the length of the word is less, it is compiled inline; otherwise referenced via a call, as shown.   
  7075. If the word must be referenced via a call, the compiler will select the most efficient of 3 types of subroutine calls to use. 
  7076. If the called word is in the lowest 96K of the dictionary,  the compiler will use the JUMP-SUBROUTINE (JSR), INDEXED WITH DISPLACEMENT mode, either through register A4 (ORG) or A3 (+64K).
  7077. If the called word is not in the lower 96K of JForth, but is within 32K of the calling instruction, the BRANCH-SUBROUTINE (BSR) mode is used.
  7078.  Otherwise,  the compiler will use the JUMP-SUBROUTINE (JSR), LONG ABSOLUTE mode.  This type of reference requires the JForth System Manager to maintain a table of all long absolute references, that they may be relocated by the Amiga Loader at startup.  This table is invisible to the programmer.   
  7079. (COMMAS)   ( -- addr )   "paren commas" 
  7080. This is the user variable that the number-formatting and printing routines check to see if they should include commas in the output stream.  If true, include commas.   
  7081. Related Words: COMMAS  NO-COMMAS   
  7082. (CR)   ( -- )   "paren carriage return" 
  7083. (CR) is the default contents of the DEFERed word CR .  (CR) outputs a carriage return and a line feed to the standard EMIT device.   
  7084. (CREATE)   ( <name> -- )   "paren create" 
  7085. (CREATE) is the default contents for the DEFERed word :CREATE .   
  7086. (CREATE) eats the next word in the input stream (parsed by the character value stored in CREATECHAR), and from it, creates a new dictionary header, in the CURRENT vocabulary.  The name is left smudged.   
  7087. Related Words: :CREATE REDEF?  
  7088. (DO)   ( limit index -- )   "paren do" 
  7089. (DO) performs similarly to (?DO), except that it performs no index/limit value checking.  This means that: 1. If the index and limit are equal, the LOOP will be executed once.  2. If the index is greater than the limit, it will LOOP until the index has been incremented and is subsequently equal to the limit.   
  7090. NOTE: this word, when used with LOOP, may be used for positive-growing LOOPS:  
  7091. (EMIT)   ( char -- )   "paren emit" 
  7092. This is an EMIT function primitive that performs single-character I/O to the CONSOLE window.  It is executed by the deferred word EMIT when in the SLOW I/O mode.   
  7093. This word transfers characters to the screen in single-character fashion. The normal I/O technique utilized in JForth is buffered, and this word is only used, oddly enough, for KEY, to echo each character typed to the user.  In the SLOW I/O mode, it is the only EMIT primitive used.   
  7094. (EMIT) will update OUT to reflect the current cursor column number.   
  7095. NOTE: (EMIT) is NOT the default contents for the DEFERed word EMIT.  See <FASTEMIT>.   
  7096. (EXPECT)   ( addr nchars -- )   "paren expect" 
  7097. Default word for EXPECT . See EXPECT .  EXPECT is deferred so that it can be changed by the user if needed.   
  7098. (FIND)   "paren find" 
  7099. ( $name lfa -- cfa true | $name false )  
  7100. (FIND) is a primitive used to locate the most recently defined occurrence of the given name. It will start searching the dictionary at the lfa passed on the stack.   
  7101. If (FIND) locates the name, it returns its CFA and a TRUE flag.   
  7102. If the word is not found, (FIND) will return the original name and a FALSE flag.   
  7103. (FIRST)   ( -- addr )   "paren  first" 
  7104. This is a user-variable that is only used in the BLOCK environment, and is initialized when the source file JU:BLOCK is compiled.   
  7105. After initialization, it contains the address of the first virtual buffer available under BLOCK.   
  7106. (ID.)   ( nfa -- )   "paren  i d dot" 
  7107. This is the default contents of the DEFERred word ID. .  It accepts the count byte address of a name-field, and TYPEs the name on the standard EMIT device.   
  7108. (INTERPRET)   ( -- )   "paren interpret" 
  7109. Run time code for INTERPRET .  This is the default contents of the DEFERed word INTERPRET.  It is the core of what is known in Forth as the "Outer Interpreter".  JForth does not have an "Inner Interpreter since it compiles directly to 68000 machine code.  (INTERPRET) is what interprets and executes the commands that you enter at the keyboard.  It is also used when compiling a file.   
  7110. (INTERPRET) gets its input from the TIB.  (INTERPRET) uses >IN to index into the TIB.  When >IN equals #TIB, or an error occurs, (INTERPRET) returns.   
  7111. After (INTERPRET) has parsed a word from the input stream, it searches first the CONTEXT, then CURRENT vocabularies.  If found, the resultant address will either be executed or compiled, based on the STATE of the system, and (INTERPRET) will continue with the next word.   
  7112. If not found, it will see if the text can be successfully converted to a number (using the current BASE) and if so, the resultant number is passed to LITERAL.   
  7113. If a number cannot be derived, the system QUITS, displaying the offending text on the console.   
  7114. Related Words: QUERY $INTERPRET  
  7115. (KEY)   ( -- char )   "paren key" 
  7116. Wait for a character from the console.  When received, return the character without echo. Flushes any pending output.  Default contents of DEFERred word KEY .   
  7117. (LEAVE)   "paren leave" 
  7118. ( -- )  ( n1 n2 --LOOP-STACK-- )  n1 and n2 are loop indices  
  7119. (LEAVE) is compiled by LEAVE.   
  7120. (LEAVE) forces immediate termination of a DO LOOP by dropping the loop indices, and jumping past the corresponding LOOP word.   
  7121. (LIMIT)   ( -- addr )   "bracket limit" 
  7122. This is a user-variable that is only used in the BLOCK environment, and is initialized when the source file JU:BLOCK is compiled.   
  7123. After initialization, it contains the address of the END of the virtual buffer area available under BLOCK.   
  7124. (LONGCFA,)   ( cfa -- )   "paren long c f a comma" 
  7125. This is the default contents for the DEFERred word LONGCFA, .   
  7126. This word is used to compile a LONG ABSOLUTE JUMP-SUBROUTINE to a cfa in the dictionary.  (LONGCFA,) will automatically create an entry in the Long Relocations table for that reference.   
  7127. (LOOP)     paren loop       
  7128. ( -- )    ( n1 n2 --LOOP-STACK-- n1 n2+1 )  
  7129. n2 = index approaching overflow 
  7130. n1 = correction value to recreate index for I 
  7131. (LOOP) is compiled by LOOP.   
  7132. (LOOP) increments n2 by 1.  If n2 overflows, the LOOP is satisfied, and execution continues once the loop indices have been dropped from the LOOP-STACK.  If n2 does not overflow, return to the address immediately following the corresponding DO code.   
  7133. (NUMBER)   ( $string -- d true | false )   "paren number" 
  7134. Default contents of deferred word NUMBER .  This converts the character string at $string to a double number using the current BASE.  If the conversion fails, false is returned.   
  7135. (OF)  "parenthesis of" 
  7136. ( case-value of-value -- case-value )   
  7137. (OF) is the internal run time function for OF used in CASE statements.  It compares the top item on the stack with a duplicate of the next thing on the stack.  If they are equal it does not branch, else it branches to the ELSE part of the OF ... ELSE structure.   
  7138. (QUIT)   ( -- )   "paren  quit" 
  7139. (QUIT) is used to terminate the currently running program and initialize the INTERPRETer to return to the CONSOLE.  When called, it has the following specific effects:  
  7140. 1. Closes all files that had MARKFCLOSE executed on them.
  7141. 2. Frees all memory blocks that had MARKFREEBLOCK executed on them.
  7142. 3. Initializes the TIB from TIB0, #TIMES variable to 1.
  7143. 4. ALIGNS the dictionary.
  7144. 5. Terminates COMPILE MODE, forcing INTERPRET MODE.
  7145. 6. Clears the USP stack.
  7146. 7. Enters the QUERY INTERPRET loop.
  7147. This   is   normally  executed  by  QUIT  and  performs  many  JForth-System initializations.   If you desire to change the operation of QUIT, you should only  supplement (QUIT), executing your code then calling (QUIT) .  When the JForth  Kernal  is TURNKEYed, the action of (QUIT) MUST BE REPLACED with the startup word for your turnkey operation.   
  7148. (QUIT)  is the default contents of the DEFERed execution word, QUIT, and may remain  so  in any version of your application that has not been distributed or  released  in  any way.  You are required to replace this cfa with  one  of  your  own definition in a TURNKEYed application.  See TURNKEY and CLONE.   
  7149. (SOURCE)   ( -- TIB #TIB )   "paren source" 
  7150. TIB  = Terminal Input Buffer address 
  7151. #TIB = Number of characters in TIB 
  7152. This primitive returns the address and length of the TIB.   
  7153. *   ( n1 n2  --  n1*n2  )   "times" 
  7154. Multiply two 32 bit numbers.   
  7155. \ Multiply 23 time 7 
  7156. 23 7 * .  ( prints 161 ) 
  7157. */   ( n multiplier divisor -- n*m/d )   "times slash" 
  7158. */ calculates n times multiplier as a double length value.  This is useful if the product would be greater than 32 bits.   
  7159. 1,000,000,000 234 567 */  ( correct ) 
  7160. 1,000,000,000 234 * 567 / ( overflows! ) 
  7161. */MOD   ( n1 n2 n3 -- n4 n5 )   "times slash mod" 
  7162. n5 = n1 times n2 and then divided by n3 
  7163. n4 = remainder 
  7164. */MOD  carries n1 times n2 as a double length value. This allows greater accuracy than would a single length intermediate product. Then n3 is divided into n1 * n2 yielding n5 quotient and n4 remainder.   
  7165. 2 5 7 */MOD  ( yields 3 1 )    
  7166. +   ( n2  n1  -- n1+n2 )   "plus" 
  7167. + adds the top two values on the stack and places the result on the stack.   
  7168. 3 4 + .   ( prints 7 
  7169. +!   ( n addr  --  )   "plus store" 
  7170. +!  adds the value n to the value stored at address addr and leaves the result at addr .   
  7171. VARIABLE VAR1 
  7172. 10 VAR1 ! 
  7173. 5 VAR1 +! 
  7174. VAR1  ?   ( prints 15 ) 
  7175. +-       "plus minus" 
  7176. ( n1  n2  --  n1 )    if n2 > 0 or n2 = 0 
  7177. ( n1  n2  -- -n1 )    if n2 < 0 
  7178. +- negates the sign of second stack value n1 if top of stack value n2 is negative. Top value n2 is then dropped.   
  7179. 5 -7 +- .   ( prints -5 ) 
  7180. +DOS   ( addr count -- )   "plus dos" 
  7181. Adds a string to the existing null-terminated string at DOS0 .  This is used when interfacing with Amiga DOS.   
  7182. " df0:c/" COUNT >DOS 
  7183. " dir" COUNT +DOS 
  7184. DOS0 0COUNT TYPE  ( print "df0:c/dir" ) 
  7185. +LOOP   "plus loop" 
  7186. Compile time: ( loop-addr do-flag -- )  
  7187. Run time:  ( inc-val  -- )   ( index limit --R-- index limit | )     
  7188. Used in DO LOOPs where you want to increase by some number other than 1.   
  7189. +LOOP checks for a do-flag at compile time and gives error if not found. +LOOP compiles (+LOOP) At run time (+LOOP) increments index by inc-val and jumps back to loop body  until index crosses boundary between limit and limit-1 ( overflows ).   
  7190. : TDO+ 50 0 DO I . 10 +LOOP ; 
  7191. TDO+   ( print 0 10 20 30 40 ) 
  7192. +SHIFT   ( a b -- a<<b )   "plus shift" 
  7193. +SHIFT is a faster smaller routine than SHIFT that does only left shifts toward the MSB. 0's are shifted into the LSB positions.   
  7194. 3 2 +SHIFT .  ( prints 12 ) 
  7195. Related Words: SHIFT ASHIFT -SHIFT U2*   
  7196. +STACK  ( n var-addr -- )   "plus stack" 
  7197. +STACK is used to PUSH items to a memory block (allocated via ALLOCBLOCK) being used as a stack.  It accepts as arguments, the value n1 to push and the address var-addr of a VARIABLE or USER-variable being used to hold the address of the allocated memory area.   
  7198. If the VARIABLE or USER-variable contains 0, +STACK will allocate a 1024-byte block to be used, sufficient for 256 cells, and place the address of the block in the storage location.  It will then push the value to the area.   
  7199. If the VARIABLE or USER-variable contains other than zero, it is assumed by +STACK to be the address of an existing memory block.
  7200. If the allocated stack area is full, and cannot accept the new element, +STACK will attempt to increase the allocated size in 1K increments.
  7201. Please see the chapter on Memory Management.   
  7202. Related Words: PUSH  POP  -STACK  
  7203. GL -      Glossary
  7204.  
  7205.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  7206.  
  7207.     Glossary    GL -  
  7208.  
  7209.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  7210.  
  7211.  
  7212.  
  7213.  
  7214.  
  7215. ,   ( n -- )   "comma"     
  7216. 'Comma'  compiles N into the dictionary at HERE and advances the dictionary pointer by 4.  It can be used to supplement CREATEd data structures in the dictionary.   
  7217. \ Create an array called sizes 
  7218. CREATE SIZES 330 , 250 ,  230 , 470 , 
  7219. 2 CELLS SIZES + @ .  ( prints 230 ) 
  7220. Related Words: ALLOT  HERE  !  @  W,  
  7221. -   ( a b -- a-b )      "minus" 
  7222. Subtract top of stack B from next to top A.  Result is put on top of stack.   
  7223. 10 7 - .  ( prints 3 ) 
  7224. Related Words: + CELL- 2-  1-  D-  
  7225. -2SORT   ( n1 n2 -- biggest smallest )   "dash 2 sort" 
  7226. Sort top two items on stack into reverse order.   
  7227. : SAFEDO  -2SORT DO ." hello" cr LOOP ; 
  7228. 10 0 SAFEDO 
  7229. 0 10 SAFEDO  ( both work ) 
  7230. Related Words: 2SORT MIN MAX  
  7231. ->   ( n <name> -- )   "to" 
  7232. Store N into a value data structure or a local variable.  VALUE data structures and local variables are self fetching so you can't use Reverse Polish words like ! .  See VALUE for example.   
  7233. File: JU:VALUE or JU:LOCALS  
  7234. -CLIST -CONSOLE -DISKFONT -GRAPHICS -ICON -INTUITION  -LAYERS 
  7235. Close the appropriate Amiga Library IF open. See LIBRARY .  This should be done before terminating an application on each library that had been opened.   
  7236. -DO "minus do" 
  7237. ( to from -- )   ( --R-- previous-loop-parameters )  
  7238. Begin a DO LOOP without checking the to and from values.   
  7239. It is often used when you want to count down instead of up, in a loop, and is normally used with -LOOP as a result.  You may also use -DO if you want to save space and time in setting up ordinary loops, where you do not need the limit checking of DO.   
  7240. The TO an FROM values are processed at run time into limit-overflow values and placed in 2 loop parameter data registers.   
  7241. \ Countdown from 10 to 0. Note 11 loops.  
  7242. : COUNTDOWN   0 10 -DO I . 1 -LOOP ; 
  7243. Note that the following loop with -DO will execute once.  The equivalent loop with DO will not execute.
  7244. : ONCE  0 0 -DO ." Hello" cr LOOP ;
  7245. Related Words: DO LOOP -LOOP +LOOP   
  7246. -DOS   ( -- )      "minus dos" 
  7247. This word has no effect in JForth.  Two libraries, EXEC and DOS are opened by the JForth startup routines, and should only be closed by BYE.  It is provided to be compatible with the word sets provided for the other library definitions.   
  7248. -DUP   ( n1  --  n1 n1 | 0 )   "dash dup" 
  7249. Duplicates the top of the stack only if it is non zero.  This can save you from having to do ELSE DROP.   
  7250. Standards:  '79 and '83 use ?DUP for this definition. FIG uses -DUP  
  7251. : MAYBECLOSE  ( filepointer -- , close if safe ) 
  7252.     -DUP IF FCLOSE THEN ; 
  7253. Related Words: ?DUP DUP XDUP IF 0=  
  7254. -EXEC   ( -- )      "minus exec" 
  7255. This word has no effect in JForth.  Two libraries, EXEC and DOS are opened by the JForth startup routines, and should only be closed by BYE.  It is provided to be compatible with the word sets provided for the other library definitions.   
  7256. -FIND ( <word> -- pfa cntadr true | 0 ) "dash find" 
  7257. FIG standard version of FIND.  Not recommended.   
  7258. File: JU:MULTISTANDARD  
  7259. -LIB   ( var-holding-lib-pointer -- )   "minus lib" 
  7260. This word is the primitive used by all the library closing routines.   
  7261. It accepts the address of a VARIABLE or USER-variable that contains the pointer to an open library.  If the var contains 0, -LIB does nothing.  The word set provided for handling Amiga libraries usually precludes the necessity for the programmer to use -LIB.   
  7262. Related Words: LIBRARY  
  7263. -LOOP   ( n -- )   "minus loop" 
  7264. -LOOP works like +LOOP but subtracts the value on the stack instead of adding it.  -LOOP is normally used with -DO for loops where the count is counting down instead of up.  See -DO  
  7265. Related Words: -DO +LOOP DO LOOP (-LOOP) (+LOOP)     
  7266. -MATHFFP -MATHIEEEDOUBBAS -MATHIEEESINGBAS -MATHTRANS -POTGO 
  7267. ( -- )  
  7268. These words will close the appropriate Amiga library, if it is open.  If not, there is no effect.   
  7269. Related Words: LIBRARY  
  7270. -ROT   ( a b c -- c a b )   "minus rot" 
  7271. Rotate the top three items on the stack in the reverse direction that ROT would.  Equivalent to but faster than using ROT twice.   
  7272. -SHIFT   ( n s -- n>>s )   "minus shift" 
  7273. Shift n by s positions to the right.   
  7274. -SHIFT is a shorter, faster version of SHIFT that only does negative shifts toward the LSB.  See SHIFT for more info.  Zeros are shifted into the MSB so be careful with negative numbers.   
  7275. 100 2 -shift . ( prints 25 ) 
  7276. Related Words: SHIFT +SHIFT ASHIFT U2/  
  7277. -STACK   ( value var-address -- )   "minus stack" 
  7278. value           = item that is searched for and removed 
  7279. var-address     = address of a variable 
  7280. -STACK is used to remove items from a memory block that is being used as a stack.  It expects the address of a VARIABLE or USER-variable that points to the allocated memory area, and the value to find and remove.  If the VARIABLE or USER-variable contains 0, nothing will happen.  Otherwise, the stack area is searched for the value, removed if found, and the FREEBYTE counter for the area updated.  If -STACK causes the stack area to become empty, it will free the memory area, clearing the pointer address that was passed as an argument.  See section on memory management.   
  7281. Related Words: ALLOCBLOCK  +STACK  PUSH  POP  
  7282. -TRAILING ( addr count -- addr count') "dash trailing" 
  7283. -TRAILING adjusts the count of a string to remove trailing blanks.  It does this by scanning backward from the last character toward the first character and the first non-blank character stops the scan.   
  7284. " Hello     " COUNT .S -TRAILING .S TYPE 
  7285. Related Words: COUNT TYPE SKIP  
  7286. .   ( n -- )   "dot" 
  7287. Print the integer number on the top of the stack.  Use the value of BASE as the current numeric base.  Print a space after the number.   
  7288. 2 3 + .  ( will print "5 " )  
  7289. Related Words: U. .R D. D.R  .HEX  BASE ? N>TEXT F.   
  7290. ."   ( <text> -- )   "dot quote" 
  7291. Print a text string terminated with a ".   
  7292. If used inside a colon definition, the text will be compiled into the word for later printing.  This word will also work outside of colon definitions although the Forth '83 standard says it should fail.   
  7293. With buffered I/O, the output may not appear until you call CR KEY or FLUSHEMIT.  See FAST .   
  7294. ." Hello world!" 
  7295. Related Words: (.")  TYPE CR  
  7296. ..  ( struct-addr <member> -- member-addr ) "dot dot" 
  7297. Return the address of a member in a 'C' like structure.  See chapter on the Amiga 'C' structure interface.   
  7298. SCREEN MY-SCREEN ( declare screen structure ) 
  7299. MY-SCREEN .. SC_RASTPORT ( -- address-rastport-member) 
  7300. File: JU:C_STRUCT  
  7301. ..!   ( n struct-addr <member> -- )   "dot dot store" 
  7302. Set the member of a structure to n.  C! , W! or ! will be used depending on the width of the member.  See chapter on the Amiga 'C' structure interface.   
  7303. NEWSCREEN MY-NEWSC ( declare screen structure ) 
  7304. 3 MY-NEWSC ..! NS_DEPTH  ( set number of bitplanes ) 
  7305. File: JU:C_STRUCT  
  7306. ..@  ( struct-addr <member> -- n ) "dot dot fetch" 
  7307. Fetch the value of a structure member.  C@ , W@ or @ will be used depending on the width of the member.  See chapter on the Amiga 'C' structure interface.   
  7308. MY-WINDOW ..@ WD_WIDTH ( fetch width of window ) 
  7309. File: JU:C_STRUCT  
  7310. .ELSE   ( -- )   "dot else" 
  7311. Conditional compilation word used with .IF . See .IF  
  7312. .ERR   ( -- )   "dot err" 
  7313. .ERR is useful when reporting errors.  It clears the stack, executes CR , then TYPEs the text at HERE, in preparation for your error message and subsequent QUIT.   
  7314. : ?HaveError   ( flag -- , quits with error message if error ) 
  7315.     IF .ERR  ." flag was not Zero!"  QUIT 
  7316.     THEN  ; 
  7317.  
  7318. \ Here is an example with the resulting printout.  
  7319. 0 ?HaveError  ok 
  7320. 1 ?HaveError 
  7321. ?HAVEERROR ? ... flag was not Zero! 
  7322. Related Words: HERE ABORT" QUIT TYPE  
  7323. .FILE   ( <filename> -- ) 
  7324. Uses DOLINES to print the contents of a file with line numbers.  Similar to TYPEILE .   
  7325. File: JU:DOLINES  
  7326. .HEX   ( n -- )   "dot hex" 
  7327. Print the top of stack as a hexadecimal, HEX , number regardless of the current base.   
  7328. DECIMAL 17 .HEX  ( prints 11 ) 
  7329. .HX   ( n -- )   "dot h x" 
  7330. Prints one digit.  This will print a digit in any base up to 36.   
  7331. Equivalent definition:  
  7332. : .HX  ( n -- ) 
  7333.     DUP 9 > IF 37 + ELSE 30 + THEN EMIT ; 
  7334. Related Words: .HEX  .S  
  7335. .IF   ( flag -- )   "dot if" 
  7336. .IF , along with .ELSE and .THEN , allows for conditional compilation. These words work like IF ELSE THEN but they are immediate words and work in the interpret state as well.  JForth source files include numerous examples of the use of these conditional words. 
  7337. .IF and related operators are NOT nestable.
  7338. false .IF  : FOO ( one way ) ; 
  7339. .ELSE  : FOO ( a different way ) ; 
  7340. .THEN 
  7341. Related Words: .IF .ELSE .NEED EXISTS?  .THEN       
  7342. .IMAGE   ( -- )   "dot image" 
  7343. .IMAGE will report whether the current image is:  
  7344. Relocatable (contains LONG-ABSOLUTE address references, and if so, how many)  
  7345. OR 
  7346. Position-Independent (the compiler has been able to use relative addressing modes for all threading).   
  7347. A LONG-ABSOLUTE reference (JSR) will be compiled only if: 1) the calling program is over 32K away from the called program...  AND 2) the called program is not resident in the bottom 96K of JForth.   
  7348. Related Words: JSR-CODE  MAP CFA,  
  7349. .MODULES   ( -- ) 
  7350. Display state of detachable modules.  See chapter on modules.   
  7351. .NEED   ( -- )   "dot need" 
  7352. .NEED  is a conditional compilation word that works with .THEN and .ELSE . If the word following .NEED is in the dictionary, .NEED will skip to the .ELSE or .THEN part of the conditional compilation structure.  If the word does not exist, it will continue processing the text that follows.   
  7353. .NEED WIERD ( WIERD ain't in the dictionary  ... )               
  7354.     : WIERD   CR ." Like wow, man. " ; 
  7355. .ELSE  cr ." this place is already weird"  ( WIERD is around)  
  7356. .THEN 
  7357. Related Words: .IF .ELSE .THEN EXISTS?  
  7358. .R   ( n width -- )   "dot r" 
  7359. Print N right justified in a field WIDTH characters wide.  This is useful for preparing formatted output like tables, etc.  If the number is wider than WIDTH it will still print all the digits.   
  7360. 742  12  .R    ( prints  ___742 ) 
  7361.    ( 7 spaces to the left ) 
  7362. Related Words: D.R . # COMMAS  
  7363. .RSTACK   ( -- )   "dot r stack" 
  7364. Print the contents of the return stack.   
  7365. File: JU:.RSTACK  
  7366. .S   ( -- )   "dot s"       
  7367. Print the contents of the data stack.  The number on the right is the top of stack.  The stack will be unchanged by the operation.  Often placed inside troublesome words when debugging.   
  7368. Related Words: DEPTH DEBUG SP@ .RSTACK  
  7369. .THEN   ( -- )   "dot then" 
  7370. Terminate a .IF or .NEED conditional construct.  See .IF  for more details.   
  7371. /   ( a b -- a/b )   "slash" or "divide" 
  7372. Divide the top two items on the stack and leave the result.  This is an integer 32 bit divide.  The answer will be truncated.  Negative results will be rounded towards zero.  Use /MOD if you want the remainder.   
  7373. 33 5 / . ( prints 6 ) 
  7374. -17 8 / . ( prints -2 ) 
  7375. Related Words: /MOD M/  CELL/  D2/  2/  W/  U/  DU2/  U2/    
  7376. /MOD   ( a b -- remainder a/b )   "slash mod" 
  7377. Performs 32 bit integer divide of A by B.  Leave remainder and quotient.   
  7378. 73 10 /MOD .S  ( prints 3 7 ) 
  7379. Related Words: /  MOD  
  7380. /STRING ( addr cnt index -- addr' cnt' )"slash string" 
  7381. /STRING indexes into the string at addr, returning the address and count of the remaining string.   
  7382. " Hello World" COUNT 6 /STRING TYPE ( prints World ) 
  7383. 0   ( -- 0 )   "zero" 
  7384. Defined as a constant to speed up compilation.   
  7385. 0"   ( <text> -- 0string )   "zero quote" 
  7386. Convert the following text to a NUL terminated string.  The text should be terminated by a ".  NUL, or zero, terminated strings are used by 'C' and are therefore needed when passing strings to the Amiga Libraries.  The parameter 0string is the address of the first character in the string.   
  7387. 0" Hello" 0COUNT TYPE 
  7388. Related Words: 0COUNT >ABS $>0 DOS0 " $APPEND 0FOPEN
  7389. 0<   ( n -- flag )   "zero less than" 
  7390. Compares the top of stack to zero.  Leave TRUE if less than zero, otherwise leaves FALSE.   
  7391. : TEST 0< IF ." Negative!" THEN ; 
  7392. -5 TEST ( print Negative!) 
  7393. Related Words: 0> 0= +-  
  7394. 0=   ( n -- flag )   "zero equals" 
  7395. Compares the top of stack to zero.  Leave TRUE if equal to zero, otherwise leaves FALSE.  Can be used like NOT to complement a flag.   
  7396. Related Words: 0> NOT IF  
  7397. 0>   ( n -- flag )   "zero greater than" 
  7398. Compares the top of stack to zero.  Leave TRUE if greater than zero, otherwise leaves FALSE.   
  7399. Related Words: 0< 0=   
  7400. 0BRANCH   ( flag --  )   "zero branch" 
  7401. 0BRANCH  is compiled into a definition by IF  UNTIL  WHILE to do a conditional branch.  If flag = FALSE, the program will branch to another location.  If flag = TRUE, execution continues with the next instruction.   
  7402. Standards: FIG, called ?BRANCH in '83 and '79 .   
  7403. Related Words: IF  WHILE  UNTIL  BRANCH  NOT0BRANCH   
  7404. 0COUNT   ( 0string -- addr count )   "zero count" 
  7405. Count the characters in a NUL terminated string.   
  7406. 0" Hello" 0COUNT TYPE 
  7407. 0FOPEN   ( 0name -- filepointer | 0 )   "zero f open" 
  7408. This word takes the address of a NULL-TERMINATED string and submits it to AmigaDOS to request it be opened as a filename.   If the file can be successfully opened, its pointer is returned, else a FALSE is returned. This pointer may be passed in other file utilities to initiate reads, writes, seeks, etc.   
  7409. Please see the chapter on File I/O for more information.   
  7410. Related Words:  FILE? FOPEN $FOPEN FREAD  
  7411. 0RP   ( -- )   "zero r p" 
  7412. 0RP initializes RP to the value in the user variable RP0 .  RP = return stack pointer. This is usually used in error recovery.   
  7413. Warning: This clears the subroutine calling stack of the 680x0 so be very careful when using this.   
  7414. Related Words: RP0 RP!   
  7415. 0SP   ( a? b? whatever -- , empty )   "zero s p" 
  7416. Clear the data stack by initializing SP to the value in the user variable SP0 .  SP = stack pointer.  Remember the top of stack is cached in D7. Only recommended for interactive use and in error recovery.   
  7417. 11 22 33 0SP  ( stack now empty ) 
  7418. Related Words: SP0 SP!  
  7419. 1   ( -- 1 ) 
  7420. Defined as a constant to speed compilation.   
  7421. 1+   ( n -- n+1 )   "one plus" 
  7422. Add one to the value n on top of the stack.
  7423. 7 1+ . ( print 8 ) 
  7424. Related Words: 2+  1- 2- 2* 2/ + -   
  7425. 1-   ( n -- n-1 )   "one minus" 
  7426. Subtract one from the value n on top of the stack.   
  7427. Related Words: + - 1+ 2+ 2- 1 2   
  7428. 2   ( -- 2 ) 
  7429. Defined as a constant to speed compilation.   
  7430. 2!  ( d addr -- )   "two store" 
  7431. Store a 64 bit double number at the given address.  Only even addresses are allowed on a 68000 system.  Use ODDD! for odd address double stores.  2! is a synonym for  D! .   
  7432. Related Words: D! ODD-D!    
  7433. 2*   ( n -- n*2 )   "two times" 
  7434. Multiply top of stack by 2.  
  7435. -5 2* . ( print -10 ) 5 2* . ( print 10 ) 
  7436. 2**N   ( n -- 2**n )   "two to the n" 
  7437. Raise two to the Nth power.   
  7438. 3 2**N . ( print '8'  = 2*2*2 ) 
  7439. File: JU:BSORT  
  7440. 2+   ( n -- n+2 )   "two plus" 
  7441. Add two to the value n on the top of the stack.   
  7442. 85  2+  .  ( prints 87 ) 
  7443. 2-   ( n -- n-2 )   "two minus" 
  7444. Subtract two from the value n on the top of the stack.   
  7445. 2/   ( n -- n/2 )   "two slash" 
  7446. Divide the top of stack by two.  This uses an arithmetic left shift which is much faster than the normal divide.   
  7447. Related Words: 2* U2* U2/ DU2/ DU2* W/ /MOD U/ M* U* D2/ / M/ DIGS/ */MOD  
  7448. 2@   ( addr -- d )   "two fetch" 
  7449. Fetch a double number from the given address.  Only even addresses are allowed. See D@ .   
  7450. Related Words: D@ ODD-D@ X@  
  7451. 2DROP   ( a b -- ) 
  7452. Drop 2 cells from top of stack.   
  7453. Standards: '83 and FIG . Called DDROP in '79 .   
  7454. Related Words: DROP  
  7455. 2DUP   ( a b -- a b a b ) 
  7456. Duplicates the top pair of stack values.   
  7457. Standards: '83 and FIG .  Called DDUP in '79 .   
  7458. Related Words: DUP  
  7459. 2OVER   ( a b c d -- a b c d a b ) 
  7460. Copies pair of numbers over top pair.    
  7461. Related Words: OVER DUP 2DUP DOVER  
  7462. 2SORT   ( n1 n2 -- smallest biggest )   "2 sort" 
  7463. Sort two numbers.   
  7464. Related Words: -2SORT MIN MAX  
  7465. 2SWAP   ( a b c d -- c d a b ) 
  7466. Swaps the top two pairs of stack values.   
  7467. Related Words: SWAP 2DUP   
  7468. 3   ( -- 3 ) 
  7469. Defined as a constant to speed compilation.   
  7470. 32K   ( -- 32768 )   "thirty-two k" 
  7471. Constant equal to 32 * 1024.    
  7472. 64K   ( -- 65,536 )   "sixty four k" 
  7473. Constant equal to 64 * 1024  
  7474. GL -      Glossary
  7475.  
  7476.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  7477.  
  7478.     Glossary    GL -  
  7479.  
  7480.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  7481.  
  7482.  
  7483.  
  7484.  
  7485. :   ( <name> -- )   "colon  " 
  7486. Start the definition of a new Forth word.  Enters COMPILE mode by setting STATE to TRUE.  The code that follows will be compiled into the word.  Sets CONTEXT and CURRENT vocabularies to the same.  Terminate with ;  which sets SMUDGE bit .   
  7487. \ Define a new Forth function then test it.  
  7488. : DOUBLE ( n -- n*2 ) 
  7489.     DUP + ; 
  7490. 7 DOUBLE .  ( prints 14 ) 
  7491. Related Words: ; CREATE  
  7492. :CREATE   ( <name> -- )   "colon create" 
  7493. :CREATE acts to create a dictionary header, using the next word available in the input stream.  It is used by: CREATE VARIABLE CONSTANT and other defining words.  :CREATE is a DEFERred word. See (CREATE).   
  7494. Related Words: (CREATE)  
  7495. :LIBRARY   ( <name> -- )   "colon library" 
  7496. Define a new Amiga Library to be called using CALL .  Any Library that has an FD file can be called from JForth.  The standard libraries have already been defined for JForth.   
  7497. :LIBRARY STUFF  ( define new library ) 
  7498. STUFF?  ( open library ) 
  7499. See the chapter on "Calling Amiga Library Routines".   
  7500. :STRUCT   ( <name> -- ) 
  7501. Defines a new structure.  See the special section on interfacing with the Amiga.   
  7502. File: JU:C_STRUCT.   
  7503. Related Words: ;STRUCT .. ..@ ..!  
  7504. ;   ( -- )   "semicolon" 
  7505. Terminate a colon definition.  Compiles EXIT into the definition being created. EXIT is the execution time procedure of ;  Clears the smudge bit. Set STATE back to zero.  Set size field to reflect size of word.  Places the system back into interpret mode.  ; is immediate.   
  7506. : HI ." Hello!" CR ; 
  7507. Related Words: EXIT : BOTH  INLINE  :CREATE    
  7508. ;STRUCT   ( -- )   "semicolon struct" 
  7509. Terminate a 'C' like structure definition.  Save a pointer to the last member defined for DST to use.  See chapter on "Accessing Amiga 'C' Structures".   
  7510. File: JU:C_STRUCT  
  7511. <   ( n1 n2 -- flag )   "less than" 
  7512. Compare n2 with n1.  Leaves TRUE if n1<n2 , FALSE if not.   
  7513. 7 23 <  ( leaves TRUE ) 
  7514. Related Words: > = U<  <=
  7515. <#   ( d -- )   "less sharp" 
  7516. <#  starts numeric output string conversion. Initializes the pointer in HLD   to point to the beginning of PAD.  Terminate with a #> . See # .   
  7517. S->D <# # # # # #S #>  ( gives at least 5 digits)  
  7518. Related Words: #S # #> SIGN HOLD  HLD  
  7519. <=   ( n1 n2 -- flag )   "less than or equal" 
  7520. Compare n2 with n1.  Leaves TRUE if n1 <= n2 , FALSE if not.   
  7521. 7 23 <=  ( leaves TRUE )
  7522. 23 23 <= ( leaves TRUE )
  7523. Related Words: > = U<  < >=
  7524. <FASTEMIT>   ( char -- )   "bracket fast emit" 
  7525. Transmits one character to the output device using buffered I/O.  This is the default contents of the DEFERred word EMIT.   
  7526. <FASTEMIT> is installed into EMIT when FAST I/O mode is entered.  To speed up printing, the character will be held in a buffer until:  
  7527. the FAST I/O buffer is filled, 
  7528. a CR is executed, 
  7529. or KEY , EXPECT or FLUSHEMIT is executed.  
  7530. This is faster than outputting characters one at a time.  <FASTEMIT> calls +OUT to adjust OUT to reflect the current cursor position.  This is done on each character.   
  7531. Related Words: EMIT  FAST  SLOW  FLUSHEMIT  
  7532. <FLUSHEMIT>   ( -- )   "bracket flush emit" 
  7533. This is the default contents of the DEFERred word, FLUSHEMIT.   
  7534. When executed in FAST mode, <FLUSHEMIT> sends any characters held in the FAST buffer to be sent to the standard EMIT device.   
  7535. =   ( n1 n2 -- flag )   "equals" 
  7536. Compares top two values n1 and n2 on stack and replaces them with  flag = true if they are equal and flag = false if they are not equal.   
  7537. Related Words: < > 0= -  
  7538. >   ( n1 n2 -- flag )   "greater than" 
  7539. Compare top two values on stack.  Leave TRUE if n1 greater than n2, otherwise leave FALSE.   
  7540. 23 7 > ( leave TRUE ) 
  7541. Related Words: < = U> IF  >=
  7542. >=   ( n1 n2 -- flag )   "greater than or equal" 
  7543. Compare top two values on stack.  Leave TRUE if n1 >= n2, otherwise leave FALSE.   
  7544. 23 7 >= ( leave TRUE )
  7545. 23 23 >= ( leaves TRUE )
  7546. Related Words: < = U> IF  >
  7547. >ABS   ( rel-addr -- abs-addr )   "to absolute" 
  7548. Convert JForth relative address to 68000 absolute address.   
  7549. JForth "addresses" are actually an offset from the base of the dictionary. This allows us to use addresses that stay the same every time we run JForth, even though JForth may load into different places in memory each time.  This makes JForth code more relocatable.  The Amiga operating system, however, uses normal 68000 addresses.  You must convert JForth relative addresses to 68000 absolute addresses before passing them to the Amiga.   
  7550. DATE-VARIABLES @ >ABS ( Amiga addr ) 
  7551. CALL DOS_LIB DATESTAMP 
  7552. Related Words: >REL S@
  7553. >BODY   ( cfa -- body )   "to body" 
  7554. Convert the CFA or tick address (start of the executable code) of a CREATE or CREATE/DOES> child to its Body address (location of the related data).  See BODY>.
  7555. >BODY will only return a meaningful result if the passed-in address points to the CFA of a word created via CREATE, either directly or via a CREATE/DOES> defining word.  This does NOT include the CFA for other data-structures, such as VARIABLEs, CONSTANTs, or VALUEs.
  7556. [Note: In JForth Version 1.2 and earlier, >BODY was a noop, implying the body and the cfa were the same!]
  7557. Related Words: ' BODY> >NAME NAME> DO-DOES-SIZE  
  7558. >DOS   ( addr count -- )   "to dos" 
  7559. Convert the string residing at ADDR  that is COUNT bytes long to a NUL-TERMINATED string in the DOS0 buffer.  This can then be passed to a DOS Library routine.   
  7560. ( moves a filename to the DOS0 buffer ) 
  7561. " df0:c/dir" COUNT >DOS 
  7562. DOS0 0COUNT TYPE 
  7563. Related Words: DOS0  +DOS  $>0
  7564. >IN   ( -- addr )   "to in" 
  7565. This is the user-variable that stores the index that INTERPRET uses to track its current place in the TIB.   
  7566. >IN is set to 0 by QUERY, and incremented as INTERPRET processes the input stream.   
  7567. : TYPE&EXEC  ( <name> -- , type name then execute. ) 
  7568.     >IN @  ( save location ) 
  7569.     CR 32 WORD COUNT TYPE CR 
  7570.     >IN !  ( restore location for interpreter to execute ) 
  7571. : FOO ." Hello" CR ; 
  7572. TYPE&EXEC FOO 
  7573. Related Words: TIB EXPECT BLK PULLTIB PUSHTIB   
  7574. >INLINE  to inline  
  7575. ( relative-altered-return-address -- ) 
  7576. ( --R-- absolute-return-address )  
  7577. >INLINE takes a relative address and converts it to an absolute address before putting it back on the return stack.   
  7578. >INLINE  is part of a set of 4 words that allow for transportable inline data words.  >INLINE puts an altered inline data address back to the top of the return stack, in the proper return stack format.  In JForth for the Amiga, the return stack contains absolute addresses, but @ and other data movement words are relative.  See chapter on transportability.   
  7579. Related Words: INLINE> INLINE@ INLINE+  
  7580. >LINK   ( cfa -- link )   "to link" 
  7581. >LINK converts a CFA to a LINK address.   
  7582. Related Words: >NAME N>LINK          
  7583. >NAME   ( cfa -- nfa )   "to name' 
  7584. >NAME converts the code-field-address of a dictionary header (that returned by ' ) to the name-field-address.   
  7585. ' SWAP  >NAME ID.  
  7586. Related Words: ' NAME>  
  7587. >NEWLINE   ( -- )   "to new line' 
  7588. Perform a CR unless the cursor is already at the start of a new line.   
  7589. Related Words: LINELIMIT OUT CR  
  7590. >PARENT   ( child-CFA -- parent-CFA )   "to parent" 
  7591. >PARENT is a JForth unique word to fill the need for a transportable way to convert a child CFA to its parent CFA .  See related words.   
  7592. Related Words: CREATE DOES>  
  7593. >R   ( n --  )   (  --R-- n )   "to r" 
  7594. >R  pops a value from top of stack and pushes the value on top of return stack.  You can use the return stack as a place to store temporary variables.  You must clean up before the end of a definition, however, or your program will crash.   
  7595. : EXAMPLE ( n m -- n+1 m ) 
  7596.     >R 1+ R> ;    ( faster than SWAP 1+ SWAP ) 
  7597. Related Words: R> X>R XR> XRDROP R@ RDROP RPICK   
  7598. >REL   ( absolute-addr -- relative-addr )   "to rel" 
  7599. Inverse of >ABS . Converts an absolute 68000 address to a relative JForth address.  Addresses returned by Amiga Library routines must be converted to relative before accessing them with JForth.   
  7600. Related Words: >ABS  
  7601. >US   ( n -- )   ( ---user-stack--- n )   "to user" 
  7602. Push N onto the User Stack.  The User Stack is another stack that can be used as a convenient place to push data.  It is used by during compilation by IF DO and other conditional words.   
  7603. Related Words: R>   >R  US> US@  
  7604. ?   ( addr  --  )   "question" 
  7605. Print the value stored at ADDR . Defined as : ? @ . ;  
  7606. VARIABLE VAR1   789 VAR1 ! 
  7607. VAR1 ? 
  7608. ?ABORT"   ( flag -- )   "question abort quote" 
  7609. ?ABORT is a JForth synonym for ABORT" .   
  7610. ?CLOSEBOX   ( -- flag ) "question close box" 
  7611. Return TRUE if the Close Box gadget has been hit in an open graphics window.  The window must have been made current using GR.SET.CURWINDOW. See chapter on Graphics and Event handling, also JD:DEMO_BOXES.   
  7612. File: JU:AMIGA_EVENTS  
  7613. ?CONTROL-D   ( -- flag) "question control d" 
  7614. Return TRUE if control D has been hit on the keyboard.  Used in the debugger to interrupt execution and enter debug mode.   
  7615. File: JU:DEBUGGER  
  7616. ?COMP   (  --  )   "question comp" 
  7617. ?COMP  issues an error message and QUITs if JForth is not in compile mode, ie. STATE is TRUE.  Use to ensure that the system is in compile mode.   
  7618. Related Words: STATE ?EXEC  
  7619. ?CSP   ( -- )   "question   c s p" 
  7620. ?CSP issues an error and QUITs if the current stack pointer position does not equal the value stored in CSP. Uses WARNING and MESSAGE.  Used for compiler security because an unbalanced stack means compilation  error. JForth uses !CSP to save the stack pointer position upon start of compilation and ?CSP to check it when finished compiling.   
  7621. Related Words: DEPTH SP@  
  7622. ?DUP   ( n -- n n | 0 )   "question dup" 
  7623. Duplicates top of stack if non-zero. Same as -DUP .   
  7624. Related Words: DUP 0=  
  7625. ?ERROR ( flag  error-number  --  ) "question error" 
  7626. ?ERROR  issues error message specified by N and QUITs if flag = true.   
  7627. Related Words: ERROR MESSAGE WARNING QUIT ABORT (ABORT)  
  7628. ?EXEC   ( -- )   "question execute" 
  7629. ?EXEC  prints error message and QUITs if system is not in execute mode. STATE = zero if system is in execute mode.  :  uses ?EXEC  
  7630. Related Words: ?COMP STATE  
  7631. ?EXIT   ( flag -- )   "question exit" 
  7632. ?EXIT will exit a word if flag on stack is true, else it will continue. RETURN is safer, since it will compile ?EXIT if not within a loop, and it will compile <?RETURN> if within any level of nested do loops.   
  7633. Related Words: EXIT RETURN ?RETURN  
  7634. ?GOTO.ERROR ( flag -- )
  7635. Jump to ERROR: label if flag is true.
  7636. File: JU:GOTO_ERROR
  7637. Related Words: GOTO.ERROR
  7638. ?LEAVE   ( flag -- ) 
  7639. LEAVE a DO LOOP if the flag is true. See LEAVE .   
  7640. Related Words: LEAVE DO LOOP RETURN  
  7641. ?LETTER   ( char -- flag ) 
  7642. If the ASCII character on the stack is alphabetic, return a TRUE; otherwise return FALSE.   
  7643. Related Words: NUMBER? ASCII  
  7644. ?OF ( value flag -- value | )
  7645. Executes the following code up to an ENDOF, and drops the value if the flag is true.  See CASE.
  7646. ?PAIRS   ( n1 n2 --  )   "question pairs" 
  7647. Tests n2 and n1 for equality. If  equal, they are discarded and execution goes on.  If not equal, an error message is given and QUIT is executed.  It is used for checking whether conditional constructs are paired correctly. Usual message is  CONDITIONALS NOT PAIRED.   
  7648. Related Words: ?DO_FLAG ?IF_FLAG AGAIN THEN ELSE LOOP  
  7649. ?PAUSE   ( -- )   "question pause" 
  7650. Pause if a key has been hit.  ?PAUSE calls ?terminal . If a key has been activated, it will stop and wait for a line of text followed by a carriage return.  It will execute the statements in that line then continue after where the  ?PAUSE was executed.  It is used by VLIST DUMP TYPEFILE and some other printing words.   
  7651. Related Words: ?TERMINAL KEY  
  7652. ?RETURN   ( flag -- )   "question return" 
  7653. ?RETURN takes a flag and returns if the flag is non-zero.  See RETURN.   
  7654. Related Words: RETURN EXIT ?EXIT EXIT     
  7655. ?STACK   ( -- )   "question stack" 
  7656. ?STACK executes ?ERROR if stack underflow or overflow occurs.   
  7657. An UNDERFLOW occurs if more items are removed from the stack than are actually on the stack.  An OVERFLOW occurs if so many items are added to the stack that it grows down into the PAD memory area.   
  7658. ?STAY   ( stay-flag -- )   "question stay" 
  7659. ?STAY is the opposite logic version of ?LEAVE; ?STAY leaves if the flag is false.   
  7660. ?TERMINAL   ( -- key-hit? )   "question terminal" 
  7661. Check the keyboard to see if a key has been hit. Return TRUE if so.  KEY can then be used to read the character.  ?TERMINAL is deferred.   
  7662. : YAK BEGIN ." Yak Yak Yak" CR ?TERMINAL UNTIL ; 
  7663. Related Words: ?PAUSE ?CLOSEBOX ?CONTROL-D  
  7664. ?VISIBLE   ( char -- flag )   "question visible" 
  7665. If the character on the stack is a visible, printable character (would cause the cursor position to move to the right one column) return TRUE; otherwise return FALSE.   
  7666. : SAFE.EMIT ( char -- , emit if visible, '.' if not ) 
  7667.     DUP ?VISIBLE NOT 
  7668.     IF DROP ASCII . THEN EMIT ; 
  7669. @   ( addr  -- n )   "fetch" 
  7670. Fetch the 32 bit value N from the address on the stack.  This is the primary operator for reading memory.  The address is a relative JForth address.  The address must be even.   
  7671. VARIABLE VAR1   567 VAR1 ! 
  7672. VAR1 @ .   ( print 567 ) 
  7673. Related Words: C@ W@ ! >REL ODD@  
  7674. @&CLOSEFILES ( var-addr -- ) "fetch and close files" 
  7675. This word accepts the address of a VARIABLE or USER-variable that contains the address of a memory block containing a list of file pointers.   
  7676. An application can easily maintain a list of its open files by calling ALLOCBLOCK and using the area as a stack, pushing each file-pointer as it receives them.  All of the files may be closed at once by passing the VARIABLE or USER-variable pointing to this area to @&CLOSEFILES.   
  7677. If the address passed to @&CLOSEFILES contains zero, there will be no effect.   
  7678. Once @&CLOSEFILES has closed the files, it will free the memory block used to store the list, and store a zero in the pointer addr.   
  7679. Related Words: @ ALLOCBLOCK FCLOSE  
  7680. @&FREEBLOCKS ( var-addr -- ) "fetch and free blocks" 
  7681. This word accepts the address of a VARIABLE or USER-variable that contains the address of a memory block containing a list of allocated memory blocks.   
  7682. An application can easily maintain a list of its allocated memory blocks by calling ALLOCBLOCK and using the area as a stack, pushing each block pointer as it receives them.  All of the blocks may later be freed at once by passing the VARIABLE or USER-variable pointing to this area to @&FREEBLOCKS.   
  7683. If the address passed to @&FREEBLOCKS contains zero, there will be no effect.   
  7684. Once @&FREEBLOCKS has freed the areas in the list, it will free the memory block used to store the list, and store a zero in the pointer addr.   
  7685. Related Words: ALLOCBLOCK FREEBLOCK  
  7686. @EXECUTE   ( addr -- )   "fetch execute" 
  7687. Fetch a CFA from the given address and execute that word.  See EXECUTE. 
  7688. GL -      Glossary
  7689.  
  7690.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  7691.  
  7692.     Glossary    GL -  
  7693.  
  7694.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  7695.  
  7696.  
  7697.  
  7698.  
  7699. ABORT   ( -- )  
  7700. Abort execution, return to outer interpreter.  No message is displayed.   
  7701. : EXAMPLE ( N -- )  1,000,000 > 
  7702.    IF  CR ." Oh my God! We're going TOO HIGH!!!" CR 
  7703.        ABORT  ( ABORT" would be better here ) 
  7704.        ( will QUIT with no "OK" message ) 
  7705.    THEN ;
  7706. ABORT is a deferred word that normally calls QUIT.
  7707. Related Words: ABORT" WARNING" .ERR QUIT  
  7708. ABORT"   ( flag <message> -- )   "abort quote" 
  7709. Display message and abort if the flag is true.   
  7710. : EXAMPLE ( N -- )  1,000,000 >  
  7711.    ABORT" Oh my God, We're going TOO HIGH!!!" ;  
  7712. Related Words: ABORT QUIT  ?ABORT" WARNING"  
  7713. ABS   ( n -- |n| )   "absolute" 
  7714. Calculate absolute value of N.  
  7715. 5 ABS .  
  7716. -5 ABS .  ( both will print positive 5 ) 
  7717. Related Words: DABS  
  7718. ABS!    ( n absolute-address -- )   "a b s store" 
  7719. Store longword, word, or byte at an absolute 68000 absolute address. Equivalent to  >REL  !  but faster.  Useful for accessing hardware.   
  7720. Related Words: >ABS ! W! C! ABS@  >REL
  7721. ABSW!   ( n absolute-address -- )   "a b s w store"  
  7722. See ABS!
  7723. ABSC!   ( n absolute-address -- )   "a b s c store"  
  7724. See ABS!
  7725. ABS@    ( absolute-address -- n )   "a b s fetch" 
  7726. ABSW@   ( absolute-address -- n )   "a b s w fetch"  
  7727. ABSC@   ( absolute-address -- n )   "a b s c fetch"  
  7728. Fetches longword, word, or byte from absolute address.  Equivalent to >REL @ but faster.  Useful for accessing hardware.   
  7729. Related Words: >ABS @ W@ C@ ABS!  
  7730. ADST   ( absolute-addr <structure> -- ) 
  7731. Dump a structure whose absolute address is on the stack.  Similar to DST which takes a relative address. See DST .   
  7732. File: JU:DUMP_STRUCT  
  7733. AGAIN   ( -- ) 
  7734. AGAIN  at execution time:  marks the end of an infinite loop and branches back to its corresponding BEGIN .  Warning - an infinite loop won't stop until QUIT or RETURN is executed.
  7735. At compile time :  compiles a BRANCH into the dictionary. Resolves the loop entry point address provided by BEGIN into a  return branch offset and stores this offset in the dictionary.  AGAIN and BEGIN are paired.  Error is detected by ?PAIRS if no match.   
  7736. \ Warning this word will never stop!!! 
  7737. : ETERNITY BEGIN ." Forever is a long time!" AGAIN ; 
  7738. Related Words: BEGIN BACK  BRANCH DO UNTIL WHILE  
  7739. ALIAS   ( <oldname> <newname> -- ) 
  7740. Create an alternative name for an existing word.   
  7741. ALIAS  2DUP DDUP 
  7742. ALIGN   ( -- ) 
  7743. Word-align the dictionary pointer DP .   
  7744. ALIGN is used at the end of any dictionary-allocation process that may have left HERE at an odd address (the 68000 CPU and JForth both require the dictionary to be word aligned).  ALIGN will allocate a byte in the dictionary if DP is odd; no effect if even.   
  7745. Related Words: C,   CARRAY   ALLOT   EVEN-UP  
  7746. ALLOCBLOCK   ( memtype size -- addr | false )  
  7747. Allocates a memory area of the given size and type and returns the JForth-relative address of the block.  If the call for memory is not successful, a FALSE flag is returned.   
  7748. The programmer will call ALLOCBLOCK to get an area of memory from the free memory list maintained by AmigaDOS.  JForth will remember the block and return it to AmigaDOS at BYE , if the programmer does not.   
  7749. This call is a direct interface to the Amiga EXEC function, AllocMem.  It returns, however, a JForth relative address, usable by all the JForth memory-reference words, such as @, C@, !, C!, etc.   
  7750. The type parameter is referenced as in Amiga literature:  
  7751. MEMF_CHIP   - memory in lowest 512K, accessible by graphics 
  7752.               and sound hardware.
  7753. MEMF_FAST   - memory above 512K, cannot be used by hardware
  7754.               chips.
  7755. MEMF_PUBLIC - memory is to be used for different tasks or 
  7756.               interrupt code, and may apply to task control 
  7757.               blocks, messages, ports, etc.
  7758. MEMF_CLEAR  - this parameter may be specified to clear the 
  7759.               memory upon allocation; otherwise no 
  7760.               initialization is done.
  7761. These  parameters  may be combined (as long as they are not self-cancelling) by  logically  ORing  them together.  For example, to indicate a global area that may be used by the graphics chips, this argument would be formed:  
  7762. MEMF_CHIP    MEMF_PUBLIC  OR 
  7763. ALLOCBLOCK  also  provides  a  range of operators that may be used to expand the  functionality  of the memory block to act as stacks and buffers, and/or automatically be freed at QUIT .   
  7764. The  address  returned  from a successful call may subsequently be passed to FREEBLOCK to return the memory to AmigaDOS when no longer needed.   
  7765. Later versions of the Amiga may support 1024K of CHIP RAM.
  7766. Related  Words:  FREEBLOCK  MARKFREEBLOCK  MEMF_CHIP  MEMF_FAST  MEMF_PUBLIC MEMF_CLEAR FREEBYTE FREEBYTEA PUSH POP -STACK +STACK SIZEMEM  
  7767. ALLOCBLOCK?   ( memtype size -- addr ) 
  7768. Identical to ALLOCBLOCK except this word reports an error and aborts if memory could not be allocated.   
  7769. ALLOT   ( numbytes -- ) 
  7770. ALLOT allocates space in the dictionary by advancing the dictionary pointer DP by N bytes.   
  7771. NOTE: if you ALLOT an odd number of bytes, the word ALIGN must be called before any operations involving HERE are allowed to occur.  It does not hurt to call ALIGN for even numbers so use ALIGN liberally.   
  7772. VARIABLE CHEAP-ARRAY 96 ALLOT  ( has room for 100 bytes )
  7773. Related Words: DP  HERE  ALIGN  
  7774. ALSO   ( voc --voc-stack-- voc voc ) 
  7775. Duplicate top of vocabulary stack.  Used to make room for vocabulary in the current context.  See the section on vocabularies.   
  7776. VOCABULARY MUSIC  ( create a new vocabulary ) 
  7777. ALSO MUSIC  ORDER ( also search the MUSIC vocabulary ) 
  7778. PREVIOUS     ( put things back the way they were ) 
  7779. AND   ( a b -- a&b ) 
  7780. Does logical  AND  on each pair of corresponding bits in A and B.  Both bits an A AND B must be 1 for bit in result to be 1.  Useful for masking data.   
  7781. HEX 7E53 FF AND .  ( print 53 ) 
  7782. : EVEN?  ( N -- flag , true if odd ) 1 AND 0= ;  
  7783. Related Words: OR XOR   
  7784. ANEW   ( <name> -- )   "a new" 
  7785. Forgets a word if already defined, no effect otherwise.  This is often used at the beginning of a file that is under development.  Every time you recompile the file, it will automatically forget the code compiled the last time.  The filename is typically appended to the prefix TASK- .  
  7786. \ Roll dice.  
  7787. INCLUDE? CHOOSE JU:RANDOM 
  7788. ANEW TASK-DICE 
  7789. : ROLL.DICE ( -- N ) 
  7790.     6 CHOOSE 1+ 
  7791. Load the file by entering:  
  7792. INCLUDE DICE 
  7793. ROLL.DICE .  
  7794. You can now edit this file, adding and changing code.  You can then include this file again and again without getting multiple definitions of your code.  Notice that the INCLUDE? is placed before the ANEW.  This is so CHOOSE won't be forgotten each time.  
  7795. One thing to remember in using ANEW is that if you load a bunch of files after loading DICE , then reload DICE, you will lose the definitions from the other files.  (The actual files will be unaffected.) This is only a problem when you are loading a file that stops because it contains a word that is undefined.  If you load the file that contains that undefined word, and then try to reload your file, the first thing ANEW will do is forget the code you just loaded.  The same word will show up missing agin.  You can while away many a rainy day stuck in this loop.  The thing to do is to first FORGET your task word.  Consider the following sequence:  
  7796. INCLUDE MYFILE 
  7797. ( assume myfile crashes because of an undefined word ) 
  7798. ( edit myfile to do an INCLUDE? for that word) 
  7799. FORGET TASK-MYFILE 
  7800. INCLUDE MYFILE 
  7801. Unless you have more undefined words, you can continue just using INCLUDE MYFILE .   
  7802. Related Words: FORGET IF.FORGOTTEN  
  7803. ANSI.BACKWARDS   ( n -- ) 
  7804. Move cursor N characters backwards.  This is only one of a number of ANSI based "terminal editing" commands that can be found in the file JU:ANSI.   
  7805. APTR   ( <name> -- )   "a pointer" 
  7806. Define a 32 bit pointer member in a structure.  See the section on Amiga 'C' structures.   
  7807. File:  JU:MEMBER  
  7808. AREGS>ABS  ( -- )   " a regs to a b s" 
  7809. Set the flag CONVERT-AREGS so that the very next Amiga CALL will convert parameters in address registers to absolute before passing them to the Amiga.  This will save you having to call >ABS excessively.  See chapter on Calling Amiga Libraries.   
  7810. ARGS   ( <library_lib> <routine_name> -- ) 
  7811. ARGS looks up arguments for an Amiga Library call and displays them.   It provides a form of automatic documentation.  It looks in the FD files so there must be one for the library you specify.  The library need not be open.   
  7812. ARGS GRAPHICS_LIB DRAW 
  7813.  
  7814. Will display:  Draw(rastPort,x,y)(A1,D0/D1) 
  7815. This tells you that the graphics DRAW routine takes 3 arguments.  Place the absolute address of a RASTPORT on the stack followed by x and y values, then use CALL to invoke the routine.  JForth will automatically build the necessary code to stuff the 68000 registers and make the call.   
  7816. Related Words: CALL DCALL    
  7817. ARRAY   ( numcells <name> -- ) 
  7818. Creates a one dimensional array of length NUMCELLS of 32 bit values starting at the next available dictionary location .  Cells are initialized at compile time to zero's.  The index of the first array item is zero just like in 'C'.  Let's create an array with 20 items.
  7819. 20 ARRAY MY-ARRAY 
  7820. The array that was created has the following stack diagram:  
  7821. MY-ARRAY ( index -- addr )  
  7822. Now lets store a value in that array and then fetch it back.
  7823. 731 12 MY-ARRAY ! ( store 731 into cell 12 of MY-ARRAY )
  7824. 0 MY-ARRAY @  ( get first cell value )
  7825. (ODE, the object oriented dialect, has a fancier type of array.)  
  7826. Related Words: ALLOT ALLOCBLOCK OB.ARRAY  ARRAYOF
  7827. ARRAYOF ( n <structure> <name> -- )
  7828. Create an array of structures.  For example:
  7829. 10 ARRAYOF GADGET MY-GADGETS
  7830. ASCII   ( <char> -- ASCII-value ) 
  7831. Converts the next character in the input stream to its ASCII equivalent and  puts the value on top of the stack .   
  7832. ASCII A .  ( print 65 ) 
  7833. ASHIFT   ( n shift-count -- n-shifted ) 
  7834. Arithmetic shift N by SHIFT-COUNT.  Shift left is shift-count is positive, right if negative.  Preserve the sign of N when shifting left by "dragging" the sign bit.   
  7835. -20 -2 ASHIFT . ( print -5 ) 
  7836. The word SHIFT is similar but does not preserve sign.   
  7837. ASM   ( -- , <wordname> )
  7838. See the chapter on 68000 ASSEMBLY.   
  7839. AUTO.INIT  ( -- ) 
  7840. Used for automatic initialization.  You write this word.  When JForth starts up, it searches the dictionary for a word called AUTO.INIT and executes the first one it finds.  If you have an initialization word that you would like called at startup, define a word called AUTO.INIT that calls the previous AUTO.INIT then calls your word.  This will add onto a chain of AUTO.INITS that initialize many parts of JForth.   
  7841. Code that allocates memory, opens files or libraries, initializes hardware, opens windows or builds tables is often called with AUTO.INIT .  The matching terminate code is then called from AUTO.TERM.  In general, DO NOT allocate memory open files or windows, etc.  at compile time. Place this code in a colon definition and use INIT words.   
  7842. Here is an example that shows how to automatically initialize a system, as well as automatically clean up on BYE or if the code is forgotten.   
  7843. ( variable to avoid double init or term ) 
  7844. VARIABLE IF-MY-INIT 
  7845. : MY.STARTUP  IF-MY-INIT @ 0= 
  7846.     IF  ALLOC.STUFF SET.STUFF 
  7847.         IF-MY-INIT ON 
  7848.     THEN 
  7849. : AUTO.INIT ( -- , add my.startup to init chain ) 
  7850.     AUTO.INIT ( important!!) 
  7851.     MY.STARTUP 
  7852. : MY.TERM  IF-MY-INIT @ 
  7853.     IF  CLEANUP.STUFF FREE.STUFF 
  7854.         IF-MY-INIT OFF 
  7855.     THEN 
  7856. : AUTO.TERM MY.TERM AUTO.TERM ; ( called on BYE ) 
  7857. IF.FORGOTTEN MY.TERM  ( call MY.TERM if forgotten ) 
  7858. Related Words: AUTO.TERM IF.FORGOTTEN  
  7859. AUTO.REQUEST  ( $body $posi $nega -- flag ) 
  7860. Put an Amiga Auto Requester on the screen.  The body will be the main message.  There will be two possible responses, one positive and one negative.  These might be "Yes" and "No", or "OK" and "Cancel".  When the user selects a response, a TRUE will be returned for a positive response, otherwise FALSE.   
  7861. File: JU:AUTO_REQUEST  
  7862. AUTO.TERM  ( -- ) 
  7863. This word is called automatically when JForth exits using BYE.  You can define a word called AUTO.TERM to cleanup your code on BYE.  See AUTO.INIT for an example of it's use.   
  7864. B->S   ( byte -- sign-extended-byte-value )  "b to s" 
  7865. Sign extend a byte value to 32 bits.   
  7866. HEX E7 B->S .HEX ( prints FFFFFFE7 ) 
  7867. Related Words: W->S S->D  
  7868. BACK   ( addr -- ) 
  7869. BACK  resolves the supplied address ADDR into a backward branch offset relative to HERE and compiles the offset into the dictionary.  It is used internally to compile UNTIL , AGAIN , etc.   
  7870. BASE   ( -- addr ) 
  7871. BASE  is a user variable that contains the current number base used for input and output number conversion. HEX stores sixteen into BASE. DECIMAL stores ten into BASE.   
  7872. The JForth ok prompt will tell you about the current base:  
  7873. ok      - decimal 
  7874. ok(hex) - hexadecimal 
  7875. ok(bin) - binary 
  7876. ok(7)   - in base 7 
  7877. To display the base in decimal without destroying contents of BASE:  
  7878. : BASE? BASE @ DUP DECIMAL . BASE ! ; 
  7879.  
  7880. DECIMAL 7 BASE ! 
  7881. 6 1 + .  ( print 10 ) 
  7882. BEGIN   ( -- )   
  7883. BEGIN  marks the beginning of a loop. May be executed indefinitely as opposed  to a DO loop which is limited to a certain number of passes.  Used with UNTIL , WHILE , REPEAT and AGAIN.   
  7884. At compile time, BEGIN places the address of the next available dictionary location onto the stack so UNTIL or REPEAT or AGAIN can compile a return branch into their definition.  Begin_flag is checked by UNTIL or REPEAT or AGAIN for a balanced loop.   
  7885. compile time  ( -- entry_point_address  begin_flag )   
  7886. entry_point_address = location of first word of loop.  
  7887. begin_flag is for compiler security.  
  7888.  
  7889. BEGIN code ( -- flag ) UNTIL ( quits when true ) 
  7890. BEGIN code  AGAIN 
  7891. BEGIN code ( -- flag ) WHILE code-if-true REPEAT 
  7892.  
  7893. : JABBER BEGIN ." Blah blah! " ?TERMINAL UNTIL ; 
  7894. BEGIN_FLAG   ( -- n ) 
  7895. A constant left by the compile time part of BEGIN and used by  the compile time part of UNTIL, REPEAT, WHILE , or AGAIN .   
  7896. BENCH  ( <forthword> -- ) 
  7897. Benchmark a word, subtracting the overhead time found using BENCH.WITH. For example, many words are benchmarked by calling them many times from a DO LOOP.  To get an accurate measurement of the word we need to subtract the time for an empty DO LOOP.   
  7898. \ Measure speed of swap.  
  7899. 1,000,000 CONSTANT 1MEG 
  7900. : TDO   1MEG 0 DO LOOP ; ( empty loop ) 
  7901. : TSWAP 1MEG 0 DO SWAP LOOP ; 
  7902. BENCH.WITH TDO 
  7903. 23 45 BENCH TSWAP 
  7904. Related Words: MEASURE BENCH.WITH '  
  7905. BENCH.WITH ( <forthword> -- ) 
  7906. Determine overhead time for benchmarking Forth words.  See BENCH for example.   
  7907. BINARY   ( -- )  
  7908. Sets user variable BASE to 2 for binary input and output numeric conversion.  The Forth ok prompt will be followed by a (bin) when BASE is set to binary.   
  7909. Related Words: HEX DECIMAL BASE  
  7910. BIT-SET?   ( n bit# -- flag ) 
  7911. Test to see if a bit in N is equal to 1. The rightmost, least significant bit is bit number zero.   
  7912. HEX 84 2 BIT-SET? ( true ) 
  7913. Related Words: SET-BIT AND OR XOR  
  7914. BL   ( -- 32 )   "b l" or "blank" 
  7915. Constant equal to the ASCII value for a blank, or space.   
  7916. : SAYAGAIN BL WORD COUNT TYPE ; 
  7917. SAYAGAIN hello  ( prints HELLO ) 
  7918. Related Words: WORD -FIND  
  7919. BLK   ( -- addr )   "b l k" 
  7920. A user-variable, used only in the BLOCK environment to hold which 1024 byte section of a SCREEN-FILE is being loaded and interpreted .  BLK = 0 if not interpreting from a screen file.   
  7921. WORD looks at BLK to determine the address of input data.  QUIT sets BLK to 0.   
  7922. Related Words: LOAD-FILE >IN BLOCK  
  7923. BLKERR   ( -- )   "block error" 
  7924. This word is the default contents for the DEFERed word, BLOCK.   
  7925. It serves to print the text at HERE, followed by the message " ... BLOCK not initialized!", finally executing QUIT.   
  7926. This sequence warns that an attempt to execute BLOCK has been made without having loaded the "JU:BLOCK" file.  This file defines the support environment for BLOCK, defining the correct handler to replace BLKERR in the vector of BLOCK.   
  7927. Related Words: BLOCK  QUIT HERE    
  7928. BLOCK   ( block# -- buffer-addr ) 
  7929. Returns the address at the start of the 1024 byte buffer numbered BLOCK# . If this block is not already loaded, it loads it from the file providing a system similar to virtual memory.  Since JForth normally uses regular ASCII text files, you must load JU:BLOCK to use this facility.   
  7930. Related Words: BUFFERADR  BLK R# LOAD (FIRST) FLUSH INCLUDE  
  7931. BODY>   ( data-addr -- CFA )   "body from" 
  7932. Convert the Body address (location of the data area) of a CREATE or CREATE/DOES> child to its CFA or tick address (start of the executable code).  See >BODY.
  7933. BODY> will only return a meaningful result if the passed-in address points to the data field of a word created via CREATE, either directly or via a CREATE/DOES> defining word.  This does NOT include the data location for other data-structures, such as VARIABLEs, CONSTANTs, or VALUEs.
  7934. [Note: In JForth Version 1.2 and earlier, BODY> was a noop, implying the body and the cfa were the same!]
  7935. Related Words: >BODY  ' >NAME >LINK  
  7936. BOTH   ( -- ) 
  7937. BOTH is an immediate compiler directive used just preceding a ; at the end of a definition.  Once stated, the compiler will verify that the word being compiled may safely be used as an inline definition.   
  7938. If so, the word is initialized such that the compiler will either compile an indirect call to it, or move it inline, depending on the value of the user-variable MAX-INLINE when it is being compiled.   
  7939. If not, a warning message is issued, informing the operator that the word cannot be compiled inline, and the word will be set as CALLED .   
  7940. : EXAMPLE  ( -- )  ROT OVER +    BOTH ; 
  7941. Related Words: ;  INLINE MAX-INLINE CFA,  
  7942. BRANCH   ( -- ) 
  7943. Used internally.  BRANCH is compiled by certain conditional words to re-direct program flow at run time. BRANCH adds a + or - offset to IP causing an unconditional jump.   
  7944. Related Words: ELSE AGAIN REPEAT   
  7945. BSIN   ( -- addr )   "b s in" or "back space in" 
  7946. Variable containing the value of the backspace character for input. Usually 08 hex is the default value.   
  7947. Useful for working with different terminals.   
  7948. Related Words: BSOUT  
  7949. BSORT   ( #items -- )   "b sort" 
  7950. Sort items using Batcher sort.  To control what gets sorted, you must set the deferred word BSORT-EXCH? .  For more information, see the file JU:BSORT and the definition of BSORT-EXCH?  
  7951. File: JU:BSORT, see also JA:SORTMERGE  
  7952. Related Words: BSORT-EXCH? 2SORT  
  7953. BSORT-EXCH? ( index-a index-b -- ) "b sort dash exchange question" 
  7954. Called from BSORT.  To use BSORT you must write a word that takes the index of two items, and exchanges them if they are in the wrong order.  Then set BSORT-EXCH? to call your word.  The items that are sorted can be anything including strings, integers, etc.   
  7955. You could, for example, have a table that contained pointers to entries in a mailing address data base.  To sort your table by zip code, write a word that accepts two indices into that table, compares the two mailing addresses they point to, then swap the table entries if they are out of order.  Then set BSORT-EXCH? to call your word.  When you then call BSORT, it will generate a pattern of indices that will eventually result in your entire table being sorted in a very short time.  Please see the demo file JD:DEMO_GSORT for another example.   
  7956. : MY-EXCH?   ( ia ib -- ) 
  7957.     2DUP OUT-OF-ORDER?  ( you must supply this word ) 
  7958.     IF EXCHANGE-THEM    ( you must supply this word ) 
  7959.     ELSE 2DROP 
  7960.     THEN 
  7961. ' MY-EXCH? IS BSORT-EXCH? 
  7962. 25 BSORT 
  7963. File: JU:BSORT  
  7964. Related Words: BSORT 2SORT ADDR.EXCH?  
  7965. BSOUT  ( -- addr )   "b s out" 
  7966. User variable containing the character used to output a backspace.  Default is 08 hex.   
  7967. Useful for working with different terminals.   
  7968. Related Words: BSIN  
  7969. BSR-CODE    ( -- 6100 , in HEX ) 
  7970. Constant equal to the machine language 68000 opcode for BSR. BSR op code = 61XX hex where XX = displacement. If XX = 00 hex then the 16 bit word following BSR is used for a displacement value. BSR = Branch Subroutine.   
  7971. Used internally for 68000 machine coding.   
  7972. Related Words: DIDCODE  JSR-CODE RTS-CODE   
  7973. BYE   ( -- )  
  7974. BYE will exit JForth, returning the memory to the system.   
  7975. As long as the programmer has utilized the JForth-supplied words for memory allocations, opening & closing files, and opening libraries, JForth will return any of these resources which are still pending.   
  7976. NOTE: Only the standard predefined libraries are cleaned-up so the programmer should take care to close any custom libraries defined with :LIBRARY.   
  7977. Related Words: AUTO.TERM  
  7978. BYTE ( <name> -- ) 
  7979. Define a byte wide structure member.  See section on Amiga 'C' Structures.   
  7980. BYTE-SWAP   ( n -- ns ) 
  7981. Swaps the lower byte-pair of n.   
  7982. HEX 1234 BYTE-SWAP . ( print 3412 ) 
  7983. Related Words: SWAP WORD-SWAP  
  7984. GL -      Glossary
  7985.  
  7986.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  7987.  
  7988.     Glossary    GL -  
  7989.  
  7990.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  7991.  
  7992.  
  7993.  
  7994.  
  7995.  
  7996. C!   ( n addr -- )   "c store" 
  7997. Store the lower 8 bits of N at address ADDR in memory.  The higher bits are discarded.  Used for storing ASCII characters or other 8 bit values.  Odd addresses can be used with this word.   
  7998. Related Words: C@ ABSC! W! !  
  7999. C@   ( addr -- n )   "c fetch" 
  8000. Fetch a byte from address ADDR in memory and leave it on the stack as a 32 bit value with the high 24 bits set to zero.  Usually used for accessing ASCII characters and other 8 bit values  
  8001. Related Words: C! @ ABSC@ W@  
  8002. CALL ( various-params <library> <routine> -- result ) 
  8003. Call an Amiga Library routine.  CALL is an IMMEDIATE word, which can ONLY be used in a colon definition.  At compile time it will look up the calling parameters in the FD file and build the appropriate code that, at run time, will:  
  8004. 1) Load the correct registers in order from the stack.  ( The order the arguments appear in source text is the same as listed in the AmigaDOS technical manuals, and with the ARGS command. )  
  8005. 2) Load Amiga register A6 with the correct library base pointer.   
  8006. 3) Call the correct location, offset from the base pointer.   
  8007. 4) Use register D0 as a 'universal' return code, moving it to top of stack.   
  8008. Please note that addresses passed to the Amiga must be converted from RELATIVE to ABSOLUTE! Please see the words >ABS and CALL>ABS for this. Please also see the chapter on Calling Amiga Library Routines for more information about CALL.   
  8009. Related Words: CALLVOID CALL>ABS AREGS>ABS :LIBRARY  DCALL >REL >ABS  
  8010. CALL>ABS ( various-params <lib> <routine> -- result ) 
  8011. Call an Amiga Library Routine.  This differs from CALL  by automatically converting any parameters passed in an address register to absolute before calling.  NULL values are left untouched.  This saves you from having to use IF>ABS .  Use ARGS to see which parameters are passed in address registers.  Generally routines in GRAPHICS, INTIUITION and EXEC work with CALL>ABS while routines in the DOS library do not because they pass addresses in data registers!  
  8012. Please see the chapter on Calling Amiga Library Routines for more information about CALL.   
  8013. Related Words: CALL AREGS>ABS ARGS CALLVOID  
  8014. CALLADR,  ( addr-of-code -- )  "call address comma" 
  8015. CALLADR,  will cause the compiler to generate, at HERE, an optimized indirect reference to the address on the stack.  The address MUST contain executable code.   
  8016. The indirect reference will be assembled in whichever of the following addressing modes is both possible and most efficient:  
  8017. 16-bit relative (BSR).  
  8018. Address-register indirect with offset (JSR).  
  8019. Long absolute  (JSR).  
  8020. Refer to the Motorola 68000 Technical Manual for more information on addressing modes.   
  8021. Related Words: CFA, HERE [ ]  
  8022. CALLVOID ( various-parameters <library> <routine> -- ) 
  8023. Call an Amiga Library routine without returning a result.  As an example the DOS library Delay() routine does not have a result.  Here is an example of calling it.   
  8024. : DELAY()  ( n -- , delay for N/50 seconds ) 
  8025.     CALLVOID DOS_LIB DELAY ; 
  8026. 100 DELAY() ( wait two seconds ) 
  8027. Please see the chapter on Calling Amiga Library Routines for more information about CALL.   
  8028. Related Words: CALL AREGS>ABS ARGS CALL>ABS  
  8029.  CANCELKEY?  ( -- n )
  8030. See the chapter on CLONE. 
  8031.  CANCELNOW?  ( --  )
  8032. See the chapter on CLONE. 
  8033. CARRAY   ( numbytes <name> -- )   "c array" 
  8034. Same as ARRAY except that the size of each element is one byte.  Creates 1 dimensional array of length N byte-sized values starting at next available dictionary location .  Bytes are initialized at compile time to zero's. The word that is created will have the following stack diagram:  
  8035. MY-CARRAY   ( index -- addr )  
  8036. Related Words: ALLOT ALLOCBLOCK ARRAY  
  8037. CASE    ( n -- n ) 
  8038. CASE is a Forth construct for selecting between several actions based on integer value.  It is used as follows:  
  8039. : EXAMPLE   ( N -- )   
  8040.     CASE   0 OF  ." None at all! "    ENDOF 
  8041.         " Still checking... " 
  8042.         1 OF  ." Only one "        ENDOF 
  8043.         13 19 RANGEOF  ." In the teens!"       ENDOF   
  8044.         dup 5,000 > ?OF  ." Lots and lots!"  ENDOF 
  8045.         ." Unexpected number = " DUP . CR 
  8046.     ENDCASE   ( ENDCASE does a DROP ) 
  8047. ;  
  8048. When executed, EXAMPLE will check the top number on the stack against each of the numbers before each of the "OF"'s.  If it matches, it will drop the number that was being checked then execute  the program after the OF up to the ENDOF , then jump to the code after the ENDCASE .  if the number does not match, it skips to the code after the ENDOF , leaving the number still on the stack.   
  8049. Similar to switch() in 'C'.   
  8050. Related Words: OF ?OF RANGEOF ENDCASE ENDOF ELSE  
  8051. CD   ( <directory-name> -- )   "c d" 
  8052. CD is used to change the current directory, an operation not possible with the DOS function.  This is a JForth program, given the same name as its AmigaDOS counterpart.   
  8053. CD is the only AmigaDOS function that is completely redefined in the JForth environment. Other AmigaDOS commands are available via DOS.   
  8054. NOTE: for memory considerations, the JForth 'CD' does not display the current directory if typed in with no pathname; this can still be done via "DOS CD".   
  8055. CD JU:     ( to actually change directories ) 
  8056. Related Words: DOS  
  8057. CELL   ( -- 4 )   "cell"   
  8058. CELL is a constant equal to the number of bytes in a stack item.  JForth uses 32 bit, 4 byte stack items so CELL = 4.   
  8059. CELL allows for code transportability between Forths of different sizes, i.e. 16 bit vs. 32 bit.   
  8060. A convenient method for defining CELL is:  
  8061. SP@ SP@ - ABS CONSTANT CELL  
  8062. Related Words: CELL+ CELL- CELLS CELL/  
  8063. CELL+   ( n -- n+cell)   "cell plus" 
  8064. Add CELL to the value on the stack.  Use for address incrementing , making transportable code .   
  8065. Related Words: CELL   
  8066. CELL-   ( n -- n-cell )   "cell minus" 
  8067. Subtract CELL from the value on the stack.   
  8068. Related Words: CELL  
  8069. CELL/   ( n -- n/cell )   "cell slash" 
  8070. Divide the value on the stack by CELL.   
  8071. Related Words: CELL  
  8072. CELLS   ( n -- n*cell )   "cells" 
  8073. Multiply the value on the stack by CELL.   
  8074. Related Words: CELL  
  8075. CFA,   ( cfa -- )   "c f a comma" 
  8076. This is a deferred word used by the compiler to compile a reference to a Forth word. See (CFA,) .   
  8077. CHOOSE   ( n -- r ) 
  8078. Choose a random number R between 0 and N-1 inclusive.   
  8079. Handy for games, statistics, random art and music.  Only good for N <= 32767. 
  8080. CHOOSE is only pseudo-random but is good enough for most simple applications.  You can even get a pseudo-gaussian distribution if you add up the results of several CHOOSE operations, say 7.   
  8081. CHOOSE uses the value in RAND-SEED for its seed.  CHOOSE will always give you the same "random" sequence for the same seed.  In a program where you want a different random sequence every time, try setting RAND-SEED to the current system time when you start the program.   
  8082. INCLUDE? CHOOSE JU:RANDOM 
  8083. : ROLL.DIE   ( -- 1-6 ) 
  8084.     6 choose 1+ 
  8085. Related Words: RANDOM WCHOOSE RAND-SEED  
  8086.  CLIST?   ( -- )
  8087. CLIST_LIB
  8088. CLIST_NAME
  8089. Used to manage the CLIST library.  See :LIBRARY.   
  8090.  CLONE  ( <wordname> -- )
  8091. Clone is used to generate a Royalty Free executable image from your Forth programs.  It is a two-pass program which first creates a call dependency tree for <wordname>, then uses the tree to build a separate program image of minimum size.   
  8092. See the chapter on CLONE. 
  8093. CLOSEALLLIBS   ( -- )   "close all libs" 
  8094. This word will close all of the standard Amiga Libraries, except for EXEC and DOS, which are closed when BYE is called.   
  8095. Note that this word is not usually needed; the preferred programming technique is to use the XXX? and -XXX words, where XXX is the name of the library.  See :LIBRARY.   
  8096. Note also that CLOSEALLLIBS will not close any additional libraries the programmer has defined with :LIBRARY.   It is the responsibility of the calling program to insure these custom libraries are closed.   
  8097. CLOSEALLLIBS is normally only used by BYE .   
  8098. Standards: JForth unique  
  8099. Related Words: BYE LIBRARY  
  8100. CLOSEFILES  ( addr -- ) 
  8101. CLOSEFILES accepts the address of a memory block (gotten via ALLOCBLOCK) which has been used to store a list of opened files, and will close each file still there.   
  8102. CLOSEFILES will not free the memory block.   
  8103. CLOSEFVREAD   ( var-addr -- )   "close f v read" 
  8104. CLOSEFVREAD accepts a variable or user-variable address that contains the location of a virtual buffer which has been used for reading ONLY.   
  8105. The memory-block serving as the buffer will be freed, and the var-address will be cleared.   
  8106. See chapter on File I/O.   
  8107. Related Words: OPENFV  READLINE  
  8108. CLOSEFVWRITE   ( file-pointer var-addr -- ) 
  8109. CLOSEFVWRITE accepts a variable or user-variable address that contains the location of a virtual buffer which has been used for writing, and the file-pointer associated with the buffer.   
  8110. If the FREEBYTE-counter for the memory-block is non zero indicating data is present, it is written to the file.  Then, the memory-block serving as the buffer will be freed, and the var-address will be cleared.   
  8111. See chapter on File I/O.   
  8112. Related Words: OPENFV  F,  FREEBYTE   
  8113. CLR-BIT   ( n bit# -- n' )   "clear bit" 
  8114. Force a bit in N to zero. BIT# determines which bit is set to zero.  BIT# = 0 refers to the least significant bit.   
  8115. Related Words: SET-BIT  
  8116. CLRCHAR   ( -- var-addr )   "clear character" 
  8117. This is a VARIABLE which contains the ASCII value used by CLS to clear the screen.   
  8118. CLS   ( -- )   "c l s" 
  8119. Clear the screen.  Fetch the ASCII value contained in the VARIABLE CLRCHAR, and send it to the standard EMIT device.   
  8120. Related Words: EMIT ASCII CLRCHAR  
  8121. CMOVE ( source-addr dest-addr count -- ) "c move" 
  8122. Move count bytes from source to destination.  The move will proceed from low to high address.  If the destination region overlaps the source region and the destination is at a higher address you may want to use CMOVE> or MOVE instead to avoid destroying data.   
  8123. For large amounts of data MOVE is much faster and will handle any overlaps automatically.   
  8124. Related Words: MOVE CMOVE> $MOVE  
  8125. CMOVE> ( source-addr dest-addr count -- ) "c move back" 
  8126. Move COUNT bytes from source to destination.  Unlike CMOVE , start with the last byte and work towards the beginning. Useful for overlapping memory areas.   
  8127. Related Words: MOVE CMOVE  
  8128. CNT>RANGE  ( n count -- n+count n ) "count to range" 
  8129. Convert a standard  VALUE COUNT  argument pair to a LIMIT INDEX argument pair (suitable for entry into a DO-LOOP).   
  8130. : FOO 10 5  CNT>RANGE  DO I . LOOP ; 
  8131. ( will print: 10 11 12 13 14 ) 
  8132. CODE   ( -- , <wordname> )
  8133. Invokes the RPN Assembler to create a new word called <wordname>.
  8134. See the chapter on 68000 ASSEMBLY.   
  8135. COLD   ( -- )  
  8136. Initialize Forth.  COLD will reset most of JForth to the same state it was in on startup or when FREEZE was last called.  The parts of JForth affected include:  
  8137. All USER-variables below SPARE (those defined in the kernal)  
  8138. Vocabulary and dictionary structures.
  8139. All MODULEs are DETACHed.  
  8140. Note that the arrangement of files, memory areas and libraries will not be affected.   
  8141. Users should be careful not to execute COLD if the system is currently executing definitions (via DEFERred words) which will be purged; the preferred method is to remove these vectors, replacing them with those which exist in the frozen image.   
  8142. Users can define an AUTO.INIT word to reset their own code when COLD is called. See AUTO.INIT .   
  8143. Related Words: ABORT COLDEXEC FREEZE  
  8144. COLDEXEC   ( -- ) 
  8145. COLDEXEC is a DEFERed word; the JForth default contents is NOOP.   
  8146. COLDEXEC may be set (via IS) to execute a programmer-defined word during COLD, just prior to the call to ABORT.  This is called when you first bring up JForth.  You can use this to have special initialization automatically occur on startup.  It is necessary to FREEZE the image after setting COLDEXEC to have it execute at the next COLD.  (This is done automatically by SAVE-FORTH).   
  8147. ' MY-INIT-WORD IS COLDEXEC     FREEZE COLD 
  8148. We recommend the use of the new AUTO.INIT facility instead of COLDEXEC.   
  8149. Related Words: COLD ABORT FREEZE AUTO.INIT  
  8150. COMPARE   ( addr1 addr2 #bytes -- result )  
  8151. Compare two strings, S1 starting at address ADDR1 , the other, S2  starting at address ADDR2 , paying attention to the case of alphabetic characters. The number of bytes to be compared is on top of the stack.   
  8152. Results are returned as follows:  
  8153. String relationship      Result 
  8154.      s1 = s2 ............  0   
  8155.      s1 > s2 ............  1 
  8156.      s1 < s2 ............ -1 
  8157. An example that uses a compiled string and a string at PAD follows:  
  8158. : BIGGERTHANLIFE? ( $string -- result ) 
  8159.     COUNT DROP " LIFE" COUNT COMPARE ; 
  8160. " MARYLIN" BIGGERTHANLIFE? . ( print 1 ) 
  8161. Related Words: TEXT=? $=  MATCH?  SCAN $-  
  8162. COMMAS   ( -- ) 
  8163. Turn on the use of commas in the outputting of numbers.  If enabled, commas occur every 3 digits in decimal and every 4 digits otherwise.   
  8164. 12345 . ( prints 12,345 ) 
  8165. Related Words: (COMMAS)  NO-COMMAS DIGS/,  
  8166. COMPILE   ( <name> -- ) 
  8167. COMPILE is an immediate, compile-only word, the use of which may be illustrated by a sample definition: 
  8168. VARIABLE USE-32BIT
  8169. : COMPILE-SIZED-FETCH  ( -- ) 
  8170.     USE-32BIT @ 
  8171.     IF    COMPILE  @            
  8172.     ( 4 bytes long, compile a @ ) 
  8173.     ELSE  COMPILE w@            
  8174.     ( 2 bytes long, compile a w@ ) 
  8175.     THEN  ; IMMEDIATE 
  8176.  
  8177. VARIABLE VAR1
  8178. USE-32BIT OFF
  8179. : GETVAL  VAR1 COMPILE-SIZED-FETCH ; 
  8180. Our hypothetical example assumes that we may be compiling for one of two memory systems...one that will need 16-bit fetches when it runs, another at 32 bits.  The variable USE-32BIT has been set to the appropriate state for the one we are doing.   
  8181. The job of the above definition is not to FETCH the correct size at compile-time, but rather to COMPILE the correctly-sized operator to be executed later, when the application actually runs.   
  8182. Related Words: IMMEDIATE  [COMPILE] LITERAL   
  8183. COMPILING?   ( -- flag ) 
  8184. Returns a flag reflecting true (if COMPILING) or false (if not COMPILING) based on  the value of the variable STATE .
  8185. Related Words: STATE ?COMP ?EXEC  
  8186. CONSOLE?
  8187. CONSOLE_LIB
  8188. CONSOLE_NAME
  8189. These are used to manage the Amiga console library .  See :LIBRARY .   
  8190. CONSOLE!   ( file-pointer -- ) "console store"
  8191. This word accepts an AmigaDOS file-pointer, and installs it into the CONSOLEIN and CONSOLEOUT variables, causing the file to become the console through which EMIT and KEY work.
  8192. Usually, the file-pointer represents an AmigaDOS console window of either type RAW: CON: or NEWCON:.
  8193. CONSOLE@   ( -- file-pointer ) "console fetch"
  8194. This word returns the AmigaDOS file-pointer currently installed as the CONSOLEOUT window.
  8195. Usually, the file-pointer represents an AmigaDOS console window of either type RAW: CON: or NEWCON:.
  8196. Related Words: EMIT KEY FOPEN  
  8197. CONSOLEIN   ( -- var-addr ) "console in"
  8198. CONSOLEIN is a variable that usually contains the AmigaDOS file-pointer through which KEY will receive characters.
  8199. Usually, the file-pointer represents an AmigaDOS console window of either type RAW: CON: or NEWCON:.
  8200. Related Words: CONSOLE! CONSOLEOUT CONSOLE@  
  8201. CONSOLEOUT ( -- var-addr ) "console out"
  8202. CONSOLEOUT is a variable that usually contains the AmigaDOS file-pointer through which EMIT will output characters.
  8203. Usually, the file-pointer represents an AmigaDOS console window of either type RAW: CON: or NEWCON:.
  8204. Related Words: CONSOLE! CONSOLEIN CONSOLE@  
  8205. CONSTANT   ( value <name>  -- ) 
  8206. Define a Forth word that will return the value when called.  The use of constants is recommended whenever possible in your code because it makes it easier to change  and easier to understand.   
  8207. 123 CONSTANT MYVAL 
  8208. MYVAL . ( print 123 ) 
  8209. Related Words: VALUE VARIABLE CREATE DOES>  
  8210. CONTEXT   (  --  addr ) 
  8211. A user-variable containing a pointer to the vocabulary which is first to be searched by FIND.  CONTEXT may be set simply by declaring the name of the vocabulary you wish to access.   
  8212. The function VLIST will display the words in the CONTEXT vocabulary.   
  8213. See the section on Vocabularies.   
  8214. Related Words: CURRENT  VLIST  ALSO  PREVIOUS  ORDER  VOCS  FIND WORDS  
  8215. CONVERT   ( d1 addr1 -- d2 addr2 )   
  8216. d1 = value accumulator 
  8217. addr1 = address 1 char before numeric string 
  8218. d2 = d1 + <addr1+1> 
  8219. addr2 = address of first non-digit 
  8220. Convert a string at address ADDR1+1 to a double number and add it to D1 . Leave the sum D2 on the stack and push the address ADDR2 of the first non-digit found on top of the stack.  You can now process the non digit and continue with another call to CONVERT .   
  8221. Related Words: NUMBER NUMBER?  
  8222. COUNT   ( $string -- addr count ) 
  8223. Take a Forth text string and return the address of the first character and the number of characters.   
  8224. Definition:   : COUNT  ( addr -- addr+1 byte )   DUP 1+ SWAP C@ ;  
  8225. Also used as a C@ with auto increment. See '83 handy reference.   
  8226. " Hello" COUNT TYPE 
  8227. CR   ( -- )   carriage return     
  8228. CR is a DEFERed execution word; see (CR). Transmits a carriage return and line feed to the selected output device .  Also flushes the FASTEMIT buffer if FAST I/O mode (line-buffered) is in effect.  
  8229. Related Words: (CR) CR? >NEWLINE FLUSHEMIT FAST EMIT  
  8230. CR?   ( -- )   carriage return ? 
  8231. Does a carriage return and line feed if the input text is near the end of a line .   
  8232. Related Words: CR  (CR) OUT >NEWLINE  
  8233. CREATE   ( <name> -- ) 
  8234. Define a new word in the dictionary.   
  8235. CREATE  creates a "header" structure in the dictionary comprised of:  
  8236. 1) a name field -- built from the next text in the input stream.   
  8237. 2) a link field -- used to tie the headers together for searching.  The link field points to the name field of the previous definition.   
  8238. 3) a size field -- used by the compiler to determine compile-time characteristics.   
  8239. 4) a code field -- contains actual 68000 assembly language which determines the run time behavior of the word.   
  8240. Words that use CREATE are called DEFINING-WORDS.  CREATE is used by all defining words, such as CONSTANT ,  :  , VARIABLE , etc... Also used with DOES> to create new data type.  See the tutorial for more information and examples.   
  8241. Related Words: CREATECHAR  CONSTANT : VARIABLE DOES> (CREATE) DO-DOES-SIZE SKIP-WORD 
  8242. CREATECHAR   ( -- var-addr ) 
  8243. This is a user-variable that holds the character that is used to parse the input stream when a dictionary name-field is being CREATEd.   This character is used as a delimiter.
  8244. Related Words: CREATE  
  8245. CSP   ( -- addr )   "c s p" 
  8246. Variable used by many of the compiling words to check the stack depth. !CSP will set CSP to the current SP value; ?CSP will later verify CSP as unchanged, or generate an error. SP = stack pointer.   
  8247. Related Words: CSP!  ?CSP  DEPTH  
  8248. CURRENT   ( -- addr ) 
  8249. CURRENT is a variable containing a pointer to the vocabulary to which newly-created words will be attached.  It is set to point to a specific vocabulary by executing  that vocabulary name, followed by DEFINITIONS.   
  8250. Related Words: ALSO ONLY VOCABULARY PREVIOUS ORDER VOCS FORTH ABORT COLD CONTEXT  
  8251. GL -      Glossary
  8252.  
  8253.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  8254.  
  8255.     Glossary    GL -  
  8256.  
  8257.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  8258.  
  8259.  
  8260.  
  8261.  
  8262.  
  8263. D!   ( d addr -- )   "d store" 
  8264. Store the 64 bit double number D at memory address ADDR.  ADDR must be even.  Use ODDD! for odd addresses.   
  8265. : DVARIABLE ( name -- , define double variable )
  8266.     VARIABLE CELL ALLOT ;
  8267. DVARIABLE DVAR1
  8268. $ 12345678.32415762 DVAR1 D! 
  8269. DVAR1 D@ D.  
  8270. Related Words: D@ D+ D- 2@ 2!  
  8271. D+   ( d1 d2 -- d1+d2 )   "d plus" 
  8272. Add two 64 bit double numbers.   
  8273. D-   ( d1 d2 -- d1-d2 )   "d minus" 
  8274. Subtract top double number from second double number.   
  8275. D.   ( d -- )   "d dot" 
  8276. Output the ASCII string for a double number. Utilizes JForth COMMAS mode (commas inserted every 3 digits in decimal; 4 digits in other bases).  See COMMAS.   
  8277. 4567884. D. ( prints 4,567,884 ) 
  8278. Related Words: COMMAS NOCOMMAS . D.R  .R U. U.R   
  8279. D.R   ( d field-size -- )   "d dot r" 
  8280. Print a double number D right justified in a field of FIELD-SIZE characters.   
  8281. 12345678.90  12 D.R 
  8282. Related Words: D. . COMMAS NO-COMMAS .R U.R U.   
  8283. D2*   ( d -- d*2 )   "d two times" 
  8284. Double number fast multiply by 2.   
  8285. Related Words: 2* *   
  8286. D2/   ( d -- d/2 )   "d two slash" 
  8287. Double number fast divide by 2.    
  8288. 10.  D2/  D. ( will print out 5 ) 
  8289. Related Words: D2*    
  8290. D<   ( d1 d2 -- flag )   "d less than" 
  8291. Compare two double numbers. Return true if D1 less than D2.   
  8292. D=   ( d1 d2 -- flag )   "d equals" 
  8293. Compare two double numbers. Return true if D1 equals D2.   
  8294. D@   ( addr -- d )   "d fetch" 
  8295. Fetch the double number D from even address ADDR.   
  8296. Related Words: ODDD@ @ C@ W@ 2@  
  8297. DABS   ( d -- |d| )   "d absolute" 
  8298. Calculate absolute value of D. 
  8299. Related Words: ABS
  8300. DCALL ( various-params <library> <routine> -- D0 D1 ) 
  8301. DCALL is functionally identical with CALL, except it returns both D0 and D1  ( -- D0 D1 ) as a  double number.   
  8302. Double number results are returned by the MATHIEEEDOUBBAS library.  See the chapter on Calling Amiga Libraries
  8303. Related Words: CALL
  8304. DDROP   ( d -- )   "d drop" 
  8305. Discards the double number D that was on top of the stack.   
  8306. Related Words: 2DROP DROP RDROP  
  8307. DDUP   ( d -- d d )   "d dup" 
  8308. Duplicates the top stack item d .   
  8309. Related Words: DUP 2DUP    
  8310. DECIMAL   ( -- ) 
  8311. Set numeric base to decimal by setting BASE to 10.   
  8312. HEX 100 DECIMAL . ( prints 256 ) 
  8313. Related Words: HEX BINARY BASE  
  8314. DEF   ( <name> -- ) 
  8315. DEF will disassemble a given Forth word in Motorola format.  See the chapter '68000 Assembly'.   
  8316. Related Words: WORDS-LIKE  DISM ADISM DUMP '  
  8317. DEFER   ( <name> -- ) 
  8318. Create a vectored word.   
  8319. DEFER creates a function that has a user variable area storage cell containing a pointer to the word it will execute when it is called. It is a vectored execution word.  Use IS to change what a deferred word will execute.  Use WHAT's to get the CFA of what a deferred word will execute.   
  8320. DEFER EXAMPLE    
  8321. EXAMPLE  ( will print nothing, calls QUIT )  
  8322. ' ORDER IS EXAMPLE  ( will set EXAMPLE  to execute ORDER ) 
  8323. EXAMPLE  ( will execute ORDER )  
  8324. WHAT'S EXAMPLE  ( will leave the CFA of ORDER )  
  8325. >NAME ID.       ( prints ORDER ) 
  8326. See the section on DEFER under Forth Tools.   
  8327. Related Words: WHAT'S   IS  GLOBAL-DEFER   
  8328. DEPTH   ( -- #of-cells-on-stack ) 
  8329. Counts the number of cells on the stack . Places the count on top of the stack .   
  8330. : CHECK-OPERATION  ( -- , monitor stack change ) 
  8331.     DEPTH >R  DO-OPERATION 
  8332.     DEPTH R> - ABS  ( calculate change ) 
  8333.     ." Stack depth changed by " . CR ; 
  8334. Related Words: US-DEPTH RDEPTH .S 0SP SP@  
  8335. DETACHMODULE   ( -- , <modulename> )
  8336. See the chapter on MODULES.   
  8337. DICTIONARYSIZE   ( -- var-addr ) 
  8338. See the chapter on CLONE.   
  8339. DIGIT   ( char base -- digit true | char false ) 
  8340. DIGIT attempts to convert the ASCII character CHAR  to a  number according to the given numeric BASE.   
  8341. If successful, it returns the converted digit and a TRUE, otherwise it leaves the unaffected CHAR and a FALSE.   
  8342. DECIMAL  ASCII 9  10  DIGIT SWAP . .  ( print 9 -1 ) 
  8343. ASCII A  10  DIGIT SWAP . . ( failed, print 65 0 ) 
  8344. Related Words: (NUMBER)    
  8345.  DISKFONT?
  8346. DISKFONT_LIB
  8347. DISKFONT_NAME
  8348. Used to manage the Amiga DISKFONT library. See :LIBRARY .   
  8349. DLITERAL   "d literal" 
  8350. Compile time:  ( d -- )  
  8351. Run time:  ( -- d )  
  8352. Compile a literal double number.  DLITERAL is an immediate word that takes a double number from the stack, and compiles it into the dictionary following DLIT .  When this code is executed, the number will be pushed to the stack.  DLITERAL is similar to LITERAL which compiles a single precision number.   
  8353. : D64K+   ( d -- d+64K , add 64K to double number on stack ) 
  8354. \ calculate double 64K at compile time 
  8355.     [ DECIMAL 64 1024 * S->D ] 
  8356.     DLITERAL     \ compile DLIT and the double number 
  8357.     D+ ;         \ and, at run time, add it to whatever 
  8358. DNEGATE   ( d -- -d )   "d negate" 
  8359. Negate the value of a double number.   
  8360. The bitwise logical operation is   -1 XOR 1+  
  8361. 3.4 DNEGATE D.  ( prints -34 ) 
  8362. Related Words: NEGATE   
  8363. DO   ( limit index  -- ) 
  8364. DO marks the beginning of a DO....LOOP instruction.   
  8365. If, at run time the limit is not larger than the index, DO will NOT execute the body of the loop; instead it will drop the terms, and jump past the corresponding LOOP.   
  8366. Standards: 83.  '79 and fig are slightly different, executing the body of the DO-LOOP at least once, regardless of limit-index relationship.   
  8367. : PRINT-0-9  ( -- )  10 0  DO  I .  LOOP  ; 
  8368. Related Words: LOOP -LOOP  +LOOP  LOOP-DROP  
  8369. DO-DOES-SIZE   ( -- N )   "do does size" 
  8370. DO-DOES-SIZE is a constant equal to the number of bytes between the CFA of a CREATE word and the data area.  It is used to define >BODY and BODY> .
  8371. Related Words: >BODY  DOES>  >PARENT  VLINK>  CREATE  CONSTANT  
  8372. DOES>   ( -- addr , at run time ) 
  8373. DOES> is used with CREATE to create new defining words in Forth.  The code following CREATE determines how the new word is created.  The code following DOES> determines what the new word does.   
  8374. We could define a simple version of constant as:  
  8375. : CONSTANT CREATE , ( save number in dictionary ) 
  8376.    DOES> @ ( fetch saved value ) ; 
  8377. 73 CONSTANT CON1  ( execute CREATE portion ) 
  8378. CON1 .  ( execute DOES> portion then print 73 ) 
  8379. Suppose we want to CREATE a word that contains an offset supplied on the stack at compile time.  This word should add the offset to a number on the stack at run time.  This is a simplified version of the structure members used for accessing Amiga 'C' structures.  Here is how that code would be produced.   
  8380. : ADDER  ( offset -- , define new kind of Forth word ) 
  8381.    CREATE   ( offset -- , how to make ) 
  8382.       ,  ( save offset in dictionary ) 
  8383.    DOES>    ( n addr -- value+offset , what to do ) 
  8384.       @ + ( fetch saved offset and add it to N ) 
  8385. 20 ADDER ADD20  ( n -- n+20 , make one ) 
  8386. 12 ADDER DOZENMORE   ( n -- n+12 ) 
  8387. 100 ADD20 .  ( now do it, print 120 ) 
  8388. 100 DOZENMORE . ( print 112 ) 
  8389. Related Words: CREATE  IMMEDIATE  
  8390. DOLINES ( <filename> -- )
  8391. Process each line of a file using a deferred word.  See the chapter on file I/O.
  8392. DOS   ( <command-line> -- )   "dos" 
  8393. This word will parse the rest of the current line of the input stream, submitting it to AmigaDOS as a CLI command line.   
  8394. Virtually any AmigaDOS command may be invoked, with the following limitations:  
  8395. 1.  AmigaDOS output will appear in the JForth window, but cannot be parsed or interrupted.  Generally, AmigaDOS commands that produce long streams of text are better executed from a CLI.  The DOS interface is primarily provided for task and file control.
  8396. 2.  Commands executed via DOS are executed in their own  environment which terminates when the command ends.  Therefore, any AmigaDOS command that changes only the local environment (like CD) will have no effect.  JForth provides its own CD for changing directories.  See CD.   
  8397. DOS COPY MYFILE RAM: 
  8398. DOS DATE 
  8399. DOS CD   ( will print the current directory )
  8400. 3.  DOS will look for the command in the C: directory.  It will not use the search path.  If you want it to look in a directory in RAM: instead of on the Workbench disk, you must assign C: to your directory in RAM.
  8401. 4.  DOS cannot be used in a colon definition because it is not IMMEDIATE.  Use $DOS instead.
  8402. Related Words: $DOS DOSCOMMAND CD  
  8403. DOS0   ( -- addr )   "dos zero" 
  8404. DOS0 returns the address of the string buffer used for converting forth-type strings to AmigaDOS compatible null-terminated strings.   
  8405. The DOS0 buffer resides in the user-area, and is 256 characters long.  A count byte is maintained 1 byte below DOS0.   
  8406. Related Words: >DOS  +DOS  
  8407.  DOS?   ( -- )    "dos question"
  8408. DOS_NAME   dos name
  8409. DOS_LIB    dos lib
  8410. Used  to  manage  the  DOS  library.  See :LIBRARY.  DOS is opened and closed automatically by JForth.   
  8411. DP   ( -- addr )   "d p" 
  8412. A user-variable used to hold the next available location in the dictionary for this user.   
  8413. DP is referenced by several high-level words, and is therefore not generally needed by the programmer.  The contents of DP are put on the stack by HERE , and incremented by ALLOT.   
  8414. Whenever the system is INTERPRETing, the contents of DP MUST BE WORD-ALIGNED!  See ALIGN.   
  8415. Standards: fig '79 '83  
  8416. Related Words: ALLOT HERE ALIGN  
  8417. DPLIMIT    ( -- addr )   "d p limit" 
  8418. User variable that holds the maximum value allowed for dictionary to grow to. Checked by ?STACK .  The data stack and the dictionary occupy the same memory area.  The stack starts at the top and grows down.  The dictionary starts at the bottom and grows up.   
  8419. Standards: JForth  
  8420. Related Words: ?STACK  DP  
  8421. DPL   ( -- addr )   "d p l" 
  8422. User variable that shows how many  digits are to the right of a decimal point when converting a character string to a number . When no decimal point is seen , NUMBER leaves -1 in DPL .   
  8423. Standards: fig '79 '83  
  8424. 23.45 DPL ?  ( prints 2 ) 
  8425. Related Words: USER INTERPRET NUMBER (NUMBER)   
  8426. DROP   ( n -- ) 
  8427. DROP discards the top value N on the stack.   
  8428. Standards: fig '79 '83  
  8429. DUP DROP  ( cancel each other out ) 
  8430. Related Words: DDROP 2DROP RDROP XDROP  
  8431. DST   ( addr <structure> -- )   "dump struct" 
  8432. Dump a structure at address ADDR using the named structure as a template. DST will display the contents of each member, whether it is signed or unsigned, its width in bytes, and its name.   
  8433. GETMODULE INCLUDES 
  8434. BITMAP MYBMAP 
  8435. 3 MYBMAP ..! BM_DEPTH 
  8436. MYBMAP DST BITMAP  ( display contents ) 
  8437. Related Words: DUMP  ..@  FILE?  
  8438. DSWAP   ( d1 d2 -- d2 d1 )    "d swap" 
  8439. or ( a b c d -- c d a b ) 
  8440. Reverses the top two pairs of numbers on the stack.  This can be used to swap two double precision numbers.   
  8441. Standards: fig '79 '83, sometimes called 2SWAP. Both are allowed in JForth.   
  8442. Related Words: SWAP 2SWAP DDUP >R  
  8443. DU2*   ( ud1 -- ud1*2 )   "d u 2 times" 
  8444. Left shift the unsigned double number UD1. MSB is shifted out and discarded. 0 is shifted in to LSB.  This can be used as a fast multiply by 2 or as a shift.   
  8445. Standards: JForth unique  
  8446. Related Words: * U* 2* U2* M*    
  8447. DU2/   ( ud1 -- ud1/2 )   "d u 2 slash" 
  8448. Right shift the unsigned double number UD1. 0 is shifted in to  MSB . LSB is shifted out and discarded.  This can be used as a fast divide by 2.   
  8449. Standards: JForth unique.   
  8450. Related Words: / */ u/ U2/   
  8451. DU<    ( d1 d2 -- flag )   "d u less than" 
  8452. Flag = TRUE if D1 is less than D2, FALSE otherwise.  Same as U< only for double numbers.   
  8453. Standards: '83  
  8454. Related Words: <  >  U<   
  8455. DUMP   ( addr u -- ) 
  8456. Display memory from  ADDR  for  U  bytes on the standard EMIT device.   
  8457. Each line displays 16 bytes in hexadecimal and ASCII forms; any control/non-printing characters in the ASCII columns will be displayed as a period .  The CONSOLE window should be set to the full screen width.   
  8458. Every 23 lines, a header is printed showing the low nibble value of the address for that column above both formats.   
  8459. DUMP allows the programmer to suspend the output; see ?PAUSE.   
  8460. Related Words: EMIT ?PAUSE   
  8461. DUP   ( n -- n n )   "doop" 
  8462. Duplicates the top item on the stack.   
  8463. Standards: fig '79 '83  
  8464. Related Words: 2DUP DDUP -DUP DUP>R ?DUP   
  8465. DUP>R   ( n -- n )  ( --R-- n )   "doop to r" 
  8466. Push a copy of N onto the return stack.  This is simply a faster way to do DUP >R   
  8467. Related Words: DUP  ?DUP >R  
  8468. ECHO ( -- addr )
  8469. If this variable is TRUE, then INCLUDE will echo each line it compiles to the screen.
  8470. ELSE   ( -- ) 
  8471. ELSE is used with IF and THEN to specify the code to execute if the conditional was false.   
  8472. : PRINT-ACCOUNT-STATUS   ( -- , good or bad news ) 
  8473.    ." Your account is in the " 
  8474.    ACCOUNT-BALANCE @  0> 
  8475.    IF   ." BLACK." 
  8476.    ELSE ." RED" 
  8477.    THEN ; 
  8478. The above example uses the convention of putting related IF ELSE and THEN words at the same level of indentation.  
  8479. Standards: FIG '79 '83.  However, the specifics of the JForth implementation is fig.  The fig models provided the most error detection and also give the most information.   
  8480. Related Words: IF THEN BEGIN WHILE UNTIL BRANCH  
  8481. EMIT   ( char -- ) 
  8482. EMIT is a DEFERed word, see (EMIT).   
  8483. The basic function of this word is to make the ASCII character appear on an output device, usually the system CONSOLE.   
  8484. ASCII X EMIT   ( Prints X ) 
  8485. Related Words: TYPE DUMP CR SPACES R D   
  8486. EMIT-TO-COLUMN   ( char column# -- ) 
  8487. Emit  CHAR to the standard EMIT device, until column# is reached by the cursor.  This word is useful for producing columnized, tabled lists.   
  8488. : 1LINER ( page# $item -- , connect item and page ) 
  8489.     CR $TYPE  ( draw item ) 
  8490.     ASCII . 40 EMIT-TO-COLUMN  ( draw bar ) 
  8491.     4 .R  ( page number ) 
  8492. 17 " Chapter 2" 1LINER 
  8493. 234 " Chapter 5" 1LINER 
  8494. Related Words: EMIT OUT >NEWLINE CR?  
  8495. ENABLE_CANCEL  ( -- addr ) 
  8496. See the chapter on CLONE.  
  8497. END   ( -- ) 
  8498. Synonym for UNTIL, see UNTIL.   
  8499. Standards: fig '79 '83 .   
  8500. Related Words: UNTIL   
  8501. END-CODE   ( -- )
  8502. See the chapter on 68000 ASSEMBLY.   
  8503. ENDCASE    ( n -- ) 
  8504. ENDCASE is the word used to end a CASE statement. See CASE.  ENDCASE is an immediate word that resolves all of the CASE forward branches.   
  8505. Related Words: CASE OF ENDOF =  
  8506. ENDOF  ( -- ) 
  8507. ENDOF is a word used in a CASE statement. See CASE.   
  8508. EOL   ( -- eol )   "e o l" or "end of line"
  8509. EOL is a CONSTANT, and returns the value recognized by the Amiga CONSOLE device as a  End-Of-Line.  You will also find this value used in files at the end of lines.   
  8510. UNIX and Amiga DOS use $0A, or "linefeed" as the EOL character.  The Macintosh, from Apple Computer, uses a $0D or "return" as an EOL.   
  8511. Related Words: CR FEMIT READLINE >NEWLINE  
  8512. EOF   ( -- EOF )   "e o f" or "end of file"
  8513. EOF is a constant returned by FKEY when an end of file has been reached.   
  8514. Related Words: FKEY  
  8515. ERASE   ( addr count -- ) 
  8516. Set  COUNT bytes beginning with  ADDR to zero.   
  8517. Standard note: JForth  
  8518. PAD 256 ERASE  ( clear 256 bytes at PAD ) 
  8519. Related Words: FILL CMOVE MOVE DO  
  8520. ERROR   ( error# -- ) 
  8521. When executed, ERROR will:  
  8522. 1.  Go to a new-line, if not already there.
  8523. 2.  Print the text currently at HERE (that which was last INTERPRETed) followed by a '?'.
  8524. 3.  If error# is non-zero, print "Message # " and the error number.
  8525. 4.  Clear the data stack and execute QUIT.   
  8526. ERROR is the standard error-exit routine for the compiler/interpreter, which passes 0 for the error number.   
  8527. The use of numbers for error codes is discouraged in JForth; the suggested method is to provide a full-text error message via ?ABORT" , .ERR , or your own error handler, executing QUIT if necessary.   
  8528. Standards: fig.  '79 and '83 use ABORT and ABORT"  
  8529. : IN-DICTIONARY?  ( -- cfa , QUITS with ? if not there ) 
  8530.     BL WORD FIND NOT 
  8531.     IF 0 ERROR 
  8532.     THEN ; 
  8533. Related Words: ABORT ABORT" ?ERROR  .ERR HERE QUIT  
  8534. ERRORCLEANUP  ( -- ) 
  8535. See the chapter on CLONE.  
  8536. EVEN-UP   ( n -- n+1 | n ) 
  8537. Increment N if odd. N remains the same if even.  If N is odd, add 1 to make it even.   
  8538. Standards: JForth unique.   
  8539. Related Words: ALIGN AND  
  8540. EXEC?   ( -- )
  8541. EXEC_LIB
  8542. EXEC_NAME
  8543. Used  to  manage  the Amiga exec library. See :Library.  The Exec library is opened automatically by JForth.   
  8544. EXECUTE   ( cfa -- )  
  8545. EXECUTE causes immediate execution of the word whose cfa (code-field-address) is on the stack.  Execution then continues at the next instruction following the call to EXECUTE .  EXECUTE uses a 68000 Jump Subroutine instruction.   
  8546. Standards: '79 '83.   
  8547. : HI ." HELLO" ; 
  8548. ' HI .S EXECUTE 
  8549.  
  8550. THE-ACTION @  ACTIONS-ARRAY @  EXECUTE   ( jump table ) 
  8551. Please note!!! If you use a "jump table" in a cloned program, you must initialize the program at run time! See Clone.   
  8552. Related Words: @EXECUTE '  
  8553. EXISTS? ( <name> -- exists-flag )  "exists question" 
  8554. EXISTS? returns a TRUE if the following word is in the dictionary.   
  8555. EXISTS? GR.INIT .IF ." Graphics loaded!" .THEN 
  8556. Related Words: FIND .NEED ' .IF  
  8557. EXIT   ( -- ) 
  8558. Exits from a colon definition by executing an RTS, Return from Subroutine, instruction.  Don't use inside DO loops .   
  8559. Standards: '79 '83 . Called ;S  in fig.   
  8560. Related Words: UNTIL WHILE  RETURN LEAVE  
  8561. EXPECT   ( addr maxchars -- ) 
  8562. Used for inputting a string.  Read up to MAXCHARS characters from current KEY device to address starting at ADDR.  EXPECT will echo characters as they are entered.  EXPECT will stop getting characters when the maximum is reached or when a Carriage Return key is hit.  EXPECT handles Backspace characters and Control-X.  The number of characters read will be available in the user-variable SPAN following the call.   
  8563. The Command Line History system works by installing a special version of EXPECT.  Use HISTORY.OFF to get vanilla traditional version.   
  8564. When using EXPECT in cloned programs, set the variable RAWEXPECTECHO if you are using RAW: windows and need EXPECT to echo characters as they are typed.   
  8565. Standards: fig '79 '83  
  8566. : GET-NAME  ( -- , put name at PAD ) 
  8567.     CR ." What is your name? " 
  8568.     PAD 80 EXPECT 
  8569.     CR ." Hello " PAD SPAN @ TYPE 
  8570. GET-NAME 
  8571. Related Words: SPAN QUERY KEY  
  8572. GL -      Glossary
  8573.  
  8574.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  8575.  
  8576.     Glossary    GL -  
  8577.  
  8578.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  8579.  
  8580.  
  8581.  
  8582.  
  8583.  
  8584. F,   ( file-pointer var-addr n -- )   "f comma" 
  8585. Send the cell N to the specified file at its current position using buffered I/O  mode, the buffer address being held in the VARIABLE or USER-variable  VAR-ADDR  .   
  8586. The 1024-byte buffer is created by a previous call to OPENFV  which also initializes the VAR-ADDR .  Buffers allocated for purposes of writing should be closed with CLOSEFVWRITE .   
  8587. See the chapter on JForth File I/O for more information on virtual file usage.   
  8588. ( store DATA in next buffer cell ) 
  8589. MYFILE @ MYBUFFER  DATA F, 
  8590. Related Words: OPENFV  CLOSEFVWRITE  FFLUSH?  
  8591. F@,   ( file-pointer -- cell )   "f fetch comma" 
  8592. Fetch the next sequential 32-bit-value from a file; the cell will be read from the current location for the file.  F@, calls FREAD; the programmer should check FERROR after to insure the value returned is valid.   
  8593. See chapter on File I/O.   
  8594. Related Words: @ FREAD  FERROR F@,?  
  8595. F@,?  ( file-pointer -- cell ) "f fetch comma question" 
  8596. This word is functionally identical to F@,  except it will print an error message and execute QUIT if an error occurs during the FREAD (calls FREAD?).   
  8597. JForth provides for optional automatic cleanup of opened files if an error forces a QUIT.  See MARKFCLOSE and UNMARKFCLOSE.   
  8598. Related Words: F@,   
  8599. FALSE   ( -- 0 ) 
  8600. FALSE is a constant which returns the value of a logical false.  Usually zero in most systems.   
  8601. Related Words: TRUE 0= IF  
  8602. FAST   ( -- )  
  8603. After FAST has been executed, the EMIT I/O will be in line-buffered mode, a highly-efficient alternative to the single-character I/O mode.  This is the default mode of CONSOLE I/O as JForth is distributed.   
  8604. In FAST mode, any characters EMITted are held in a buffer until either:  
  8605. 1) The buffer is full.   
  8606. 2) CR , CR? , or FLUSHEMIT is executed.   
  8607. 3) Input is requested by KEY , EXPECT .   
  8608. FAST acts to install its own vectors in the EMIT vector.   
  8609. Any characters EMITted in FAST mode will update OUT (via +OUT) to reflect the current cursor column number.   
  8610. Related Words: SLOW <FASTEMIT> CONSOLE EMIT KEY FLUSHEMIT  
  8611. FBLK    ( -- addr )   "f b l k" 
  8612. This is a USER-variable, used to hold the file-pointer for the ASCII file currently being INCLUDEd.   
  8613. FBLK should not normally be altered by the programmer.   
  8614. Related Words: INCLUDE  
  8615. FCLOSE   ( file-pointer -- )   "f close" 
  8616. FCLOSE will close the specified file.  Files should be closed when you are through using them.  When the user executes BYE, any open files will be closed.   
  8617. See the chapter on File I/O.   
  8618. MYFILE @ FCLOSE 
  8619. Related Words: FOPEN  $FOPEN  
  8620. FCLOSEVAR  ( var-addr -- ) 
  8621. If you use a variable to hold the address of  a file pointer, this will close the file then clear the variable.  It first checks to make sure the variable does not contain zero. 
  8622. VARIABLE MY-FILEID
  8623. NEW FOPEN RAM:TESTFILE
  8624. MY-FILEID !  \ save pointer in variable
  8625. MY-FILEID FCLOSEVAR  \ now close it if open
  8626. MY-FILEID FCLOSEVAR  \ yes, this is safe
  8627. Related words:  FCLOSE FREEVAR 
  8628. FENCE   ( -- addr ) 
  8629. FENCE is a user-variable which may be set to an address below which FORGET will issue a warning.   
  8630. FENCE may be set by the programmer, but is automatically set by  the JForth System Manager to the current HERE in the following situations:  
  8631. 1) By FREEZE (executed by SAVE-FORTH).   
  8632. 2) If FORGET will lower the dictionary below the currently frozen FENCE.   
  8633. ( cautions if FORGETting below AARDVARK ) 
  8634. ' AARDVARK FENCE ! 
  8635. Related Words: FORGET FREEZE SAVE-FORTH  
  8636. FERROR   ( -- var-addr )   "f error" 
  8637. FERROR is a user variable which provides the programmer an alternate means (other than return codes) for checking for file operation errors.   
  8638. Each of the 3 primary file system primitives, FREAD, FWRITE and FSEEK clear FERROR at their start, and adjust it upon completion; if used, it should be checked as soon as the call returns.   
  8639. MYFILE @  PAD  256 FREAD 
  8640. FERROR @ abort" Error in file read" 
  8641. Related Words: FREAD  FWRITE  FSEEK  
  8642. FFLUSH?   ( file-pointer var-addr -- ) 
  8643. Flush the contents of the virtual buffer to disk.  The variable should contain the address of a buffer which must have been opened by OPENFV .   
  8644. See chapter on File I/O  
  8645. Related Words: OPENFV  CLOSEFVWRITE  F,  
  8646. FIG-NOT   ( n -- 1 | 0 )   "fig not" 
  8647. If n=0 then leave 1 on stack otherwise leave a zero.   
  8648. Standard: FIG  
  8649. Related Words: NOT 0= IF  
  8650. FILE?   ( <name> -- )   "file question" 
  8651. FILE? is used to identify the file that a word was compiled from, and optionally allows the programmer to search that file for instances of the same text.   
  8652. In order for FILE? to work for the words from a given file, that file had to have been compiled with FILEHEADERS enabled.  This is the default state for JForth as distributed.  When FILEHEADERS contains a non-zero value, special dictionary entries are created marking the beginning and end of the file.  (4 colons are appended to the name, i.e. ::::MYFILE, to mark the beginning; the end is noted by 3 semi-colons...;;;).   
  8653. Once the file has been identified and opened, its text is searched for instances of the word's name.  If found, that line will be EMITted along with each following non-blank line.  The search for another instance will resume when an empty line is encountered.   
  8654. As the source is not supplied for words below TASK, this utility cannot be used for kernal primitive words, approx. the first 30K of the image.  These filenames begin with J and end with either .I or .ASM .  JCOMPILER.I and JKERNAL.ASM are examples of these files.   
  8655. FILE? :STRUCT 
  8656. Related Words: FILEHEADERS  EACH.FILE?
  8657. FILEHEADERS   ( -- addr ) 
  8658. This user-variable is examined by INCLUDE to see if the programmer desires file headers, those required for the operation of FILE? .  You can save some space in the dictionary by turning FILEHEADERS OFF but then FILE? won't work.   
  8659. FILEWORD   ( <filename> -- addr ) 
  8660. FILEWORD operates similarly to WORD, in that it parses the input stream, moving suitable text to HERE, however, it uses parsing rules that allow a filename with spaces to be passed to AmigaDOS.   
  8661. If the first word that it sees starts with a double-quote '"' then it will parse up to the next double-quote, skipping over any spaces.   
  8662. : FOPEN  FILEWORD $FOPEN ; 
  8663. FOPEN "df1:icons are silly" 
  8664. The resultant string may be subsequently null-terminated and moved to the DOS0 buffer with:   ( -- addr )  COUNT >DOS  
  8665. Related Words: COUNT >DOS WORD HERE FOPEN $FOPEN  
  8666. FILL   ( addr u byte -- ) 
  8667. Fill U bytes of memory starting at ADDR with BYTE .   
  8668. PAD 256 BL FILL   ( put 256 blanks at PAD ) 
  8669. Related Words: C! ERASE ! MEM! CMOVE  
  8670. FIND   ( $addr -- $addr 0 | cfa -1 | cfa 1 )   
  8671. FIND searches the CONTEXT vocabulary for the string at $addr, and returns whether it was found, and if so, whether it is an IMMEDIATE word.   
  8672. 0 means the word was not found. The original name address will be returned.   
  8673. If the word was found. A 1 or a -1 and the word's CFA is returned.   
  8674. 1 means the words is IMMEDIATE.  INTERPRET uses this when compiling to decide whether to immediately execute the word it finds.   
  8675. -1 means the word is not IMMEDIATE.
  8676. If the search is not successful, AND the user-variable SEARCH-CURRENT is non-zero, the search will also be performed in the CURRENT vocabulary.   
  8677. : SHOWDEF  ( <name> -- , disassemble word if found ) 
  8678.     BL WORD  FIND 0= 
  8679.     IF $TYPE ."  could not be found!" CR QUIT 
  8680.     THEN DISM ; 
  8681. SHOWDEF DUP 
  8682. Related Words: WORDS-LIKE FILE? FORGET  
  8683. FIND-DATA   ( addr count n -- ) 
  8684. Beginning with  ADDR  , search for  COUNT  bytes, looking for the 32-bit-value  N.  Note that  ADDR  MUST be WORD-aligned, and that only such addresses are checked.  The addresses containing matching cells are printed on the standard EMIT device.   
  8685. Related Words: SCAN  
  8686. FIND-WDATA   ( addr count w -- ) 
  8687. This is functionally identical to FIND-DATA, except that it searches for WORD-sized data.  See FIND-DATA.   
  8688. FLD   ( -- addr ) 
  8689. User variable for controlling field length in numeric output.   
  8690. FLUSHEMIT   ( -- ) 
  8691. FLUSHEMIT is used in FAST mode to force the EMIT buffer to be EMITted even though it is not full, and an end-of-line character has not yet been received.   
  8692. Related Words: FAST  SLOW EMIT  
  8693. FOPEN   ( <filename> -- file-pointer | 0 )   "f open" 
  8694. Open a file by name.  Return zero if file could not be opened.  The programmer should ALWAYS check the returned value from FOPEN.   
  8695. Please see the chapter on File I/O for details.   
  8696. FOPEN RAM:MYFILE  ( open existing file ) 
  8697. DUP 0= ABORT" File could not be opened!" 
  8698.  
  8699. NEW FOPEN RAM:HOTNEWS  ( open new file ) 
  8700. Related Words: FILEWORD DOS0 NEW HERE FREAD FWRITE 0FOPEN $FOPEN FCLOSE  
  8701. FORGET   ( -- )  
  8702. FORGET deletes definitions from the dictionary . The specified definition and  all definitions following up to the end of the dictionary are forgotten.   
  8703. If you would like the contents of a file to automatically be forgotten when you REinclude the file, use ANEW which calls FORGET.   
  8704. If you would like a word to be called if something is forgotten use IF.FORGOTTEN.  This can be important if you are forgetting code that has allocated memory or opened files, etc. and want to clean up before losing your pointers.   
  8705. If you need to redefine what FORGET does, define a word called [FORGET] that calls [FORGET] .  This will get called by FORGET. See [FORGET].   
  8706. : FOO ." Hello" cr ; 
  8707. : GOO 23 + . ; 
  8708. FORGET FOO 
  8709. FOO ( won't find FOO or GOO ) 
  8710. Related Words: ANEW IF.FORGOTTEN [FORGET] FIND WORDS  
  8711. FREAD ( file-pointer addr max-to-read -- #bytes | -1 ) 
  8712. FREAD will read from the specified file at its current location, placing the contents at RELADDR.  FREAD will read until MAX-TO-READ bytes have been read, or end-of-file, whichever occurs first.   
  8713. FREAD always returns a value.  If the call was successful, it returns the number of bytes #BYTES that were read in If an error occurred, it returns -1.   
  8714. An error is also indicated by a non-zero value in the user-variable FERROR, immediately following the call.   
  8715. See chapter on File I/O.   
  8716. MYFILE @ PAD 256 FREAD 
  8717. PAD SWAP DUMP  ( dump stuff read ) 
  8718. Related Words: FOPEN  0FOPEN  FSEEK   FREAD?  
  8719. FREAD?   ( file-pointer addr max-to-read -- #bytes ) 
  8720. FREAD? is functionally identical with FREAD with one exception; if an error occurs during the read operation, FREAD? will print "Error on file read!" and execute QUIT.   
  8721. JForth provides for optional automatic cleanup of opened files if an error forces a QUIT.  See MARKFCLOSE and UNMARKFCLOSE.   
  8722. For further information, see FREAD.   
  8723. MYFILE @  PAD  256  FREAD? .  
  8724. Related Words: FREAD  QUIT  MARKFCLOSE  UNMARKFCLOSE  
  8725. FREEBLOCK   ( memblock -- ) 
  8726. FREEBLOCK is used to return memory to the Amiga memory manager that had been previously allocated with ALLOCBLOCK.  It performs housekeeping functions along with the JForth Memory Manager and should therefore be done ONCE AND ONLY ONCE for each previous ALLOCBLOCK call.   
  8727. At BYE, The JForth Memory Manager will return all memory-blocks allocated with ALLOCBLOCK that had NOT been returned via FREEBLOCK.  JForth also provides for automatic cleanup of allocated memory areas if an error forces a QUIT.  See MARKFREEBLOCK and UNMARKFREEBLOCK.   
  8728. See section on Memory Management.   
  8729. Related Words: ALLOCBLOCK  MARKFREEBLOCK  UNMARKFREEBLOCK  FREEVAR
  8730. FREEBLOCKS   ( memory-block -- ) 
  8731. FREEBLOCKS accepts the address of a memory block previously allocated via ALLOCBLOCK, which contains a list of other memory blocks.   
  8732. FREEBLOCKS will proceed through such a list, closing each memory block. The memory block used to store the list will not be freed.   
  8733. Related Words: FREEBLOCK  @&FREEBLOCKS  
  8734. FREEBYTE  ( memory-block -- contents-of-counter ) 
  8735. A 32-bit storage location is available for each memory block allocated; the contents of which are returned by FREEBYTE.  This is used to keep track of data when the memory block is used as a stack or a virtual file buffer.   
  8736. The FREEBYTE-counter is initialized to zero when the memory-block is allocated, and update automatically by PUSH POP +STACK -STACK FVREAD and FVWRITE.   
  8737. See section on Memory Management for details.   
  8738. MYSTACK @  FREEBYTE  CELL/  ( #cells on MYSTACK ) 
  8739. Related Words: FREEBYTEA  PUSH  POP  +STACK  -STACK  
  8740. FREEBYTEA  ( memory-block -- address-of-counter ) 
  8741. FREEBYTEA returns the address of the FREEBYTE-counter for a memory-block. This is particularly useful if the programmer is using the FREEBYTE-counter for custom purposes and wishes to update its value.   
  8742. 0  MYMEMBLK @  FREEBYTEA  ! 
  8743. ( now FREEBYTE will return 0 ) 
  8744. FREECELL   ( memory-block -- freecell ) 
  8745. This is functionally identical to  FREEBYTE  , except that it returns the offset of the next free CELL, based on the FREEBYTE-counter.   
  8746. FREEVAR  ( var-addr -- ) 
  8747. If you use a variable to hold the address of allocated memory, this will free the memory then clear the variable.  It first checks to make sure the variable does not contain zero. 
  8748. VARIABLE BIG-BUFFER
  8749. MEMF_CLEAR  2000 ALLOCBLOCK
  8750. BIG-BUFFER !  \ save pointer in variable
  8751. BIG-BUFFER FREEVAR  \ now free it if allocated
  8752. BIG-BUFFER FREEVAR  \ yes, this is safe
  8753. Related words:  FREEBLOCK FCLOSEVAR 
  8754. FREEZE   ( -- )  
  8755. FREEZE is used to snapshot important JForth system variables which, at COLD-start time, define:  
  8756. 1) The most recently defined word in the dictionary, and the resulting VOCABULARY structure.   
  8757. 2) The vectors for the following DEFERed system words:  
  8758. EMIT        KEY         ?TERMINAL   CR          QUIT 
  8759. INTERPRET   FIND        :CREATE     NUMBER      ID.  
  8760. SOURCE      BLOCK       'WORD       LONGCFA,    CFA, 
  8761. FLUSHEMIT   COLDEXEC    ABORT 
  8762. 3) All USER-variables defined below TASK.   
  8763. Even though the dictionary may be extended, and the above vectors altered by the programmer, their contents at the last  FREEZE  will be restored by COLD.   
  8764. FREEZE is called automatically by SAVE-FORTH or if FORGET lowers the dictionary below that saved by the last 'FREEZE'.   
  8765. Related Words: SAVE-FORTH  FORGET  COLD  FENCE  
  8766. FSEEK  ( file offset mode -- prev-position | -1 )   
  8767. FSEEK is used to move the current location in a file at which subsequent calls to FREAD and FWRITE will operate.   
  8768. The mode parameter, defined with the same names as referenced in the Amiga technical literature, is one of three types:  
  8769. mode                interpret positional value as 
  8770. OFFSET_BEGINNING   offset from beginning of file 
  8771. OFFSET_END         offset from end of file 
  8772. OFFSET_CURRENT     offset from current position 
  8773. See chapter on File I/O for details.   
  8774. ( move 5 bytes forward ) 
  8775. MYFILE @  5 OFFSET_CURRENT   FSEEK .  
  8776. Related Words: FREAD  FWRITE  
  8777. FSEEK?  ( file offset mode -- prev-position ) 
  8778. FSEEK? is functionally identical with FSEEK with one exception; if an error occurs during the seek operation, FSEEK? will print "Error on file seek!" and execute QUIT.   
  8779. JForth provides for optional automatic cleanup of opened files if an error forces a QUIT.  See MARKFCLOSE and UNMARKFCLOSE.   
  8780. For further information, see FSEEK.   
  8781. FWRITE  ( file addr #bytes -- #bytes-written | -1 ) 
  8782. FWRITE will write #bytes from reladdr to the file specified by file-pointer  at its current location.   
  8783. FWRITE always returns a value.  If the call was successful, it returns the number of bytes that were written; if an error occurred, it returns -1.  An error is also indicated by a non-zero value in the user-variable FERROR, immediately following the call.   
  8784. See chapter on File I/O.   
  8785. Related Words: FOPEN  0FOPEN  FSEEK   FWRITE?  
  8786. GETMODULE   ( -- , <modulename> )
  8787. See the chapter on MODULES.   
  8788. GLOBAL-DEFER   ( <name> -- ) 
  8789. Just like DEFER except DEFER stores its vector in the user area while GLOBAL-DEFER stores its vector in the dictionary.  This distinction is important in multi-tasking Forths.   
  8790. See section on DEFER.   
  8791. Related Words: WHAT'S   IS  DEFER   
  8792. GRAPHICS?  ( -- )
  8793. GRAPHICS_LIB
  8794. GRAPHICS_NAME
  8795. Used to manage the Amiga Graphics Library . See LIBRARY .   
  8796. GL -      Glossary
  8797.  
  8798.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  8799.  
  8800.     Glossary    GL -  
  8801.  
  8802.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  8803.  
  8804.  
  8805.  
  8806.  
  8807.  
  8808. HERE   ( -- addr ) 
  8809. Places the contents of DP (pointer to the next available dictionary location) onto the parameter stack.  Indicates size of COMPILED image from the beginning of the kernel.  The next word that is compiled will go "here".   
  8810. CREATE FOO HERE  ( start simple array ) 
  8811. 23 , 987 , 1722 ,  ( lay in some data ) 
  8812. HERE SWAP - CELL/ CONSTANT NUM_FOO 
  8813. ( figure out how many cells are in FOO ) 
  8814. HEX   ( -- )  
  8815. Sets user BASE to 16 decimal . All number input and output conversions will be done in hex .   
  8816. DECIMAL 10 HEX . ( will display  A  )  
  8817. Related Words: DECIMAL BINARY COMMAS BASE $  
  8818. HICASE  ( -- n ) "hi case" 
  8819. HICASE is a CONSTANT used to determine the desired characteristics of output ASCII case.  See OUTPUT-CASE.   
  8820. HIDEMODULE   ( -- , <modulename> )
  8821. See the chapter on MODULES.   
  8822. HOLD   ( char -- ) 
  8823. Add the ASCII character to the number being converted to a text string. Used by # to store ASCII characters in memory.   
  8824. : .TIME ( time -- ) 
  8825.     S->D <# # # ASCII : HOLD #S #> TYPE ; 
  8826. 1032 .TIME  ( prints 10:32 ) 
  8827. Related Words: <#  #   #S   #> COMMAS  
  8828. I   ( -- index ) 
  8829. Place current DO LOOP index on stack .   
  8830. NOTE: this is the only approved method of retrieving the index value of the currently running DO-LOOP.   
  8831. : PRINT-0-TO-9  ( -- )  10 0 DO  I .  LOOP CR ; 
  8832. Related Words: J IK DO LOOP +LOOP -DO -LOOP   
  8833.  ICON?
  8834. ICON_LIB
  8835. ICON_NAME
  8836. Manage the Amiga Icon Library. See :Library  
  8837. ID.   ( nfa -- )   "i d dot" 
  8838. Print the name of the Forth word whose NFA is on the stack.  COUNT TYPE won't work because of the smudge bits, etc.   
  8839. Standards: fig '79 '83. Called .NAME or .ID in some '83 systems.   
  8840. ' NEGATE >NAME ID.  
  8841. IF  ( flag -- ) 
  8842. Execute the following code if the flag is true (non-zero).  If the flag is false, then skip forward to the next ELSE or THEN.  IF may be used during COMPILE MODE only, and will generate an error if used otherwise.   
  8843. : TEST  ( n -- , print based on N ) 
  8844.     DUP 10 > 
  8845.     IF . ."  is bigger than 10!" CR 
  8846.     ELSE . ." is small." CR 
  8847.     THEN 
  8848. IF is an IMMEDIATE word and will execute immediately in COMPILE MODE.  It has no effect on the data stack, but will store data needed to resolve the branch on a special stack called the "User Stack".   
  8849. Compile time: user stack: ( -- if-flag address )  
  8850. Related Words: ELSE THEN = TRUE BEGIN ?PAIRS  
  8851. IF-NOT   ( flag -- ) 
  8852. Operates identically to IF , except the boolean flag satisfying the run-time branch is reversed.   
  8853. Standards: JForth unique.  Simply a faster and smaller  NOT IF .   
  8854. IF>ABS ( relative-addr -- absolute-addr ) "if to abs" 
  8855. Convert address UNLESS it is NULL, ie. zero.  This is typically used with Amiga routines that use an address or a NULL.  The NULL has a special meaning and should not be converted.   
  8856. Related Words: >ABS >REL IF>REL  
  8857. IF>REL ( absolute-addr -- relative-addr ) "if to abs" 
  8858. Convert address UNLESS it is NULL, ie. zero.  NULL is often used as a flag so it must be preserved, not converted.   
  8859. Related Words: >ABS >REL IF>ABS  
  8860. IFLEAVELONG   ( -- var-addr )
  8861. See the chapter on CLONE.   
  8862. IK   ( -- 3rd-loop-out-index ) 
  8863. Retrieve the index of the loop  in which it is nested 3 deep. If I is for the current loop and J is for the next outer loop, then IK is for the loop next further out.   
  8864. Standards: JForth unique  
  8865. : EXAMPLE  ( -- ) 
  8866.     3 0  
  8867.     DO   4 0  
  8868.        DO  5 0  
  8869.           DO  IK . J . I . CR 
  8870.           LOOP 
  8871.        LOOP 
  8872.     LOOP ; 
  8873. In the above example, the leftmost number will change the most slowly because it is the index of the outer loop.   
  8874. IMMEDIATE   ( -- )  
  8875. Changes the word just compiled to be immediate.  The programmer, by making a definition IMMEDIATE, sets the word to be executed, rather than compiled, when found within a colon definition.  This is useful for extending the compiler.   
  8876. : PRINT-HERE  ( -- , prints current DP, even while compiling ) 
  8877.     HERE .  
  8878. ; IMMEDIATE 
  8879. : FOO 23 DUP PRINT-HERE + ;  ( will print HERE now ) 
  8880. To cause an IMMEDIATE word to be compiled, it should be preceded with [COMPILE] .   
  8881. : FANCY-PRINT-HERE  ( -- , fancier version ) 
  8882.     ." Here = " [COMPILE] PRINT-HERE 
  8883. IMMEDIATE?   ( nfa -- flag ) 
  8884. Given the name-field-address of a dictionary header, return whether it is compiled as an IMMEDIATE definition.   
  8885. ' LITERAL >NAME IMMEDIATE?  ( -- true  )  .  64  ok 
  8886. ' DROP    >NAME IMMEDIATE?  ( -- false )  .  0  ok 
  8887. INCLUDE    ( <filename> -- ) 
  8888. Input Forth code from the given file.  This is used to compile source code from a file.  If an INCLUDE command is encountered in a file it will include that file then continue with the original file.  If you want to INCLUDE a file that has spaces in the name, then put the filename in double quotes.   
  8889. INCLUDE RAM:X  ( compile what's in RAM:X ) 
  8890. INCLUDE "RAM:SPACEY FILE" 
  8891. INCLUDE?  ( <name> <filename> -- ) "include question" 
  8892. INCLUDE the given file if the Forth word named is not already compiled. This is useful if you need a word from a file, and want to compile it if it's not already loaded.   
  8893. INCLUDE? MSEC JU:MSEC 
  8894. INCLUDE? GR.INIT JU:AMIGA_GRAPH 
  8895. If you are using ANEW in a file, you should place the INCLUDE? commands before you call ANEW .   
  8896. Related Words: EXISTS? FILEWORD  
  8897. INIT-USP   ( -- )  ( ? --US-- )   "init   u s p"
  8898. Initialize the user stack.  JForth incorporates a third stack mainly for use in compiling DO LOOP and other control structures.   
  8899. Standards: JForth unique.   
  8900. Related Words: US@ >US US>   
  8901. INITCLONE   ( -- )
  8902. See the chapter on CLONE.   
  8903. INITIALIMAGESIZE   ( -- var-addr )
  8904. See the chapter on CLONE.   
  8905. INLINE   ( -- ) 
  8906. INLINE is an immediate compiler directive used to inform the compiler that the user wishes this word to always be compiled inline; i.e. the entire body of the definition (minus any trailing RTS) will be copied to HERE when later compiled. This avoids the overhead of a subroutine call and is thus faster.   
  8907. INLINE may only precede the ; marking the end of a colon definition, and will cause the compiler to verify that the word may safely be compiled in this manner.   
  8908. If so, the word will be marked INLINE by setting bit 31 in the size-field. Once marked, the word will unconditionally be compiled inline when referenced in later colon definitions.   
  8909. If not, a warning message is issued, informing the operator that the word cannot be compiled inline, and the word will be set to CALLED .   
  8910. Standards: JForth unique.   
  8911. : EXAMPLE  ( -- )  ROT OVER +    INLINE ; 
  8912. : FOO 23 34 45 EXAMPLE * . ; 
  8913. ( EXAMPLE will be expanded inline in FOO, not called. ) 
  8914. Related Words: ;  BOTH  
  8915. INLINE+ ( n -- ) ( addr -- addr+n ) 
  8916. INLINE+ adds the top of the data stack to the value on return stack. INLINE+ is one of a set of 4 words used to improve the  readability and transportability of programs that use inline data.  
  8917. INLINE@   ( -- inline-data-address )   "inline fetch" 
  8918. INLINE@ returns the address of the inline data.   
  8919. INLINE+ INLINE> >INLINE   ( INLINE is not related )    
  8920. INLINE>   ( absolute-address --R-- )  
  8921. ( -- inline-data-address ) 
  8922. INLINE> takes the return stack absolute address, converts it to a relative address, then moves it to the data stack.   
  8923. Related Words: INLINE+ INLINE@ >INLINE   ( INLINE is not related )    
  8924. INTERPRET   ( -- ) 
  8925. This is a DEFERed word that is used to process a line of Forth input.  See (INTERPRET).   
  8926. Related Words: $INTERPRET QUIT COMPILING? INTERPRET?  QUERY  (INTERPRET)  
  8927. INTERPRETING?   ( -- flag ) 
  8928. Returns true if STATE is zero, ie. interpreting, false if STATE is true, ie. compiling.  When you are inside a colon definition, STATE is true. Usually used in IMMEDIATE words that behave differently when interpreting or compiling.   
  8929. Related Words: STATE ?COMP  
  8930.  INTUITION?      intuition question
  8931. INTUITION_LIB   intuition lib
  8932. INTUITION_NAME  intuition name
  8933. Used for managing the INTUITION Library. See :LIBRARY.   
  8934. IS   ( cfa <name> -- )   "is" 
  8935. IS provides the mechanism for setting the action vector for a DEFERed word.  See DEFER.   
  8936. ' DROP IS EMIT 
  8937. ( sets the deferred word EMIT to execute DROP ) 
  8938. Related Words: DEFER CFA,  
  8939. J   ( -- index ) 
  8940. Used in nested DO LOOPs.  Gets the index of the DO LOOP one level above.   
  8941. : TESTJ   2 0 DO  3 0 DO I . J . LOOP LOOP ; 
  8942. TESTJ  ( Prints    0 0 1 0 2 0  <CR> 0 1 1 1 2 1 ) 
  8943.                    I J I J I J       I J I J I J 
  8944. Related Words: I IK DO LOOP  
  8945. KEY   ( -- char ) 
  8946. KEY is used by programs to obtain single-character input; this is taken from the AmigaDOS file-pointer stored in the variable CONSOLEIN, waiting until a key has been pressed.   
  8947. KEY is a DEFERred execution word and is normally set to (KEY).  Any word that replaces (KEY) should call FLUSHEMIT to force out any stored up characters.   
  8948. : PAUSE ." Hit key to continue: " KEY DROP ; 
  8949. If you clone a program with KEY, you may want to open a RAW: window to get immediate response.  See CONSOLE! .   
  8950. Related Words: ?TERMINAL EXPECT EMIT (KEY)  
  8951. LATEST   ( -- nfa ) 
  8952. Returns the name-field of the most recently created dictionary header in the CURRENT vocabulary.   
  8953. : FOO ;    LATEST ID.  ( Prints "FOO" ) 
  8954. Related Words: CURRENT HERE  
  8955.  LAYERS?
  8956. LAYERS_LIB
  8957. LAYERS_NAME
  8958. Standards: JForth internal  
  8959. Used to manage the LAYERS library. See :LIBRARY .   
  8960. LEAVE    ( -- ) 
  8961. LEAVE a DO LOOP.  Used in the form  : ... DO ... LEAVE ... LOOP  ; At run time LEAVE causes immediate exit from the loop with which LEAVE is  associated .   
  8962. : SCAN-MAX  ( max  -- , scan until found or max reached. ) 
  8963.     0 DO 
  8964.         IS-FOUND?  ( -- true_if_found ) 
  8965.         IF ." Found at " I . CR LEAVE ( quit loop ) 
  8966.         THEN 
  8967.     LOOP ; 
  8968. Related Words: DO LOOP +LOOP RETURN  
  8969. LIBVERSION   ( -- addr ) 
  8970. LIBVERSION is a user-variable, accessed by the XXX? functions (where XXX is the name of an existing LIBRARY, GRAPHICS? for example).   
  8971. The JForth Library Manager normally opens the latest version of an existing library, but will settle for any version number.   
  8972. To specify a particular version, the programmer should place the desired version number in LIBVERSION, just prior to calling the appropriate XXX? word.   
  8973. Standards: Amiga unique  
  8974. Related Words: :LIBRARY DOS  
  8975. LIMIT   ( -- addr ) 
  8976. LIMIT is applicable only to the BLOCK or SCREEN environment, and returns the address of the end of the virtual buffer area.   
  8977. PREV @ LIMIT =   \ check to see if time to 'circle' around 
  8978. Related Words: FIRST  BLOCK  BUFFER  (LIMIT)  
  8979. LINESFILLV  "lines fill virtual" 
  8980. ( file-pointer memory-block max-char-count -- #chars-actually-read )  
  8981. This word is used to fill a memory area with ASCII text from a specified file.  The file should contain standard EOL characters; the area is filled to a line boundary.  The memory block MUST have been previously allocated via ALLOCBLOCK.   
  8982. LINESFILLV accepts 3 parameters:  
  8983. 1) A file-pointer specifying the file to read.   
  8984. 2) The address of a memory-block to put the data read from the file.   
  8985. 3) The byte-count of the memory block area.   
  8986. LINESFILLV is used by the READLINE function.  See READLINE and the chapter on File I/O.   
  8987. Standards:  JForth unique  
  8988. Related Words: OPENFV READLINE FWRITE FREAD FSEEK  
  8989. LINK>   ( lfa -- cfa )   "link to c f a" 
  8990. LINK> converts the link-field-address of a word to the corresponding code-field-address.   
  8991. ' TASK  >LINK     ( derives the lfa of TASK ) 
  8992. ( lfa -- ) LINK>  ( puts it back to the cfa of TASK ) 
  8993. Related Words: >LINK  >NAME  NAME> VLINK>'  
  8994. LIT   ( n --inline-- ) ( -- n )   "lit" 
  8995. LIT is compiled when the compiler must create code that serves to push a literal value to the stack at run-time.  The value to be pushed is compiled in the dictionary after a call to LIT .   
  8996. Standards: fig '79 83  
  8997. Related Words: LITERAL INLINE@  
  8998. LITERAL  
  8999. Compile mode:   ( n -- ) Pops the value n from the stack, and compiles it such that it will be pushed at run-time.   
  9000. Interpret mode: ( n -- n )  LITERAL has no effect when INTERPRETING.   
  9001. LITERAL allows certain calculations to be performed once at compile time and stores only the result, along with a run-time operator, LIT, to push the result to the stack.  This frees us from having to perform that same calculation repeatedly at run-time just to keep pushing the same value to the stack.   
  9002. NOTE: LITERAL should not be used if the data to be compiled represents the address of a JForth entity.  See the discussion of ALITERAL in the CLONE chapter.
  9003. Standards: fig '79 83  
  9004. : TEN-DOZEN  ( -- ten-dozen )  [ 10 12 * ]  LITERAL   ; 
  9005. Related Words: [ ] COMPILE IMMEDIATE LIT  
  9006. LOAD   ( screen# -- ) 
  9007. LOAD a screen of Forth code.  LOAD is only applicable to the BLOCK or SCREEN environment; this word is not available in the standard JForth system...the source file JU:BLOCK must be compiled in ASCII-file format to gain access to LOAD.   
  9008. LOAD causes interpretation to be redirected to the specified SCREEN of the file being pointed to by the user-variable SCR-FILE.   
  9009. LOADing will continue to the next SCREEN of the file if the operator --> is encountered during interpretation of the current SCREEN.   
  9010. Otherwize, LOAD will return when the end of the current SCREEN is reached, at which time interpretation will continue from wherever the LOAD command was invoked.   
  9011. Standards: '83  
  9012. Related Words: BLK >IN LIMIT BLOCK FIRST  
  9013. LOCASE 
  9014. LOCASE is a CONSTANT used to determine the desired characteristics of output ASCII case .  See OUTPUT-CASE.   
  9015. LONGCFA,   ( cfa -- )   "long c f a comma" 
  9016. LONGCFA, is a DEFERred word; it normally executes (LONGCFA,) which acts to compile a long absolute JUMP-SUBROUTINE to the cfa on the stack.   
  9017. Of the 3 types of calls available to the JForth compiler, this is the least preferred as it is slightly larger and slower and requires relocation.   
  9018. For these reasons, LONGCFA, is only invoked by the compiler when the distance from the destination address is too great for the preferred methods to be practical.   
  9019. Standards: JForth internal  
  9020. \ works, but wastes time and space.  
  9021. : HARD-VLIST ( -- ) [ ' VLIST LONGCFA, ] ; 
  9022. Related Words: CFA,  (LONGCFA,)   
  9023. LOOP   ( -- ) 
  9024. This is used with DO to form a loop that executes a specified number of times.  Each time through the LOOP the index is incremented until it reaches the limit, at which point execution proceeds past the LOOP command.  Use +LOOP if you want to add more than 1 to the loop index.  See DO .   
  9025. : HI ( -- , print HIYA 10 times) 
  9026.     10 0 DO 
  9027.         CR ." HIYA " 
  9028.     LOOP ;  
  9029. Related Words: DO +LOOP -LOOP  
  9030. LPLACE ( string-addr string-cnt destination-addr -- ) 
  9031. LPLACE is functionally identical to PLACE, except it will unconditionally preserve ASCII-case across the move.  See PLACE.   
  9032. LWORD    ( char -- addr ) 
  9033. LWORD is functionally identical to WORD, except it will unconditionally preserve ASCII-case across the move.  See WORD.   
  9034. GL -      Glossary
  9035.  
  9036.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  9037.  
  9038.     Glossary    GL -  
  9039.  
  9040.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  9041.  
  9042.  
  9043.  
  9044.  
  9045.  
  9046. M*   ( n1 n2 -- d1 )   "m times" 
  9047. Multiply two signed single precision numbers N1 and N2 together and leave the signed double product D1.   
  9048. M/   ( d n1 -- rem n2 )   "m slash" 
  9049. M/ divides a signed divisor N1 into a signed double dividend D  to yield a signed remainder REM and the signed quotient N2.   
  9050. M/MOD   ( d1 n1 -- rem d2 )   "m slash mod" 
  9051. Divides a signed value N1 into a signed double-value D1 and returns the signed remainder  REM  and a signed double quotient D2 .   
  9052. MAKEMODULE   ( size -- , <modulename> )
  9053. See the chapter on MODULES.   
  9054. MAKEUCASE   ( -- addr ) 
  9055. This is a user-variable which controls whether WORD will convert all alphabetic characters to upper-case.   
  9056. Normally, all dictionary headers are created by WORD.  FIND for reasons of speed is CASE-SENSITIVE.  Therefore, all words, by convention, are converted to upper-case as they are moved to HERE, by WORD.   
  9057. The programmer, should he/she wish to receive lower-case strings at HERE, may either set (and restore when done) the contents of MAKEUCASE himself, or use the supplied version LWORD, which does this automatically.   
  9058. MAKEUCASE @   FALSE MAKEUCASE ! 
  9059. PROGRAMMERS-GET-WORD 
  9060. MAKEUCASE ! 
  9061. Related Words: WORD  LWORD HERE  
  9062. MAP   ( -- ) 
  9063. MAP displays general information concerning current memory allocation and dictionary utilization, number of vocabularies, relocation information, file usage, the setting of the current MAX-INLINE variable, the state of the modules, and whether the HASHed vocabulary search is in use..   
  9064. MARKFCLOSE   ( file-pointer -- )   "mark f close" 
  9065. MARKFCLOSE places the FILE-POINTER in a list of file-pointers that will be closed if the system executes QUIT .   
  9066. This mechanism allows an application to automatically clean up its resources in both of the two possible paths most programs may take... normal completion or an irrecoverable error abort.   
  9067. Note that if the application terminates normally, it should clear this AUTO-CLOSE status for the file by executing UNMARKFCLOSE for each file it had previously marked.   
  9068. FOPEN ?DUP       \ get the filename, did it open? 
  9069. IF  DUP MYFILE ! \ yes, save pointer in my variable 
  9070.     MARKFCLOSE     \ set it to auto-close at quit 
  9071.     RUN-MY-PROGRAM \ do whatever I want to do with the file 
  9072.     MYFILE @ DUP   \ need to do TWO thing to the pointer...  
  9073.     UNMARKFCLOSE   \ remove it from the QUIT list...  
  9074.     FCLOSE         \ and close the file 
  9075. ELSE ." Can't open the file!" 
  9076. THEN 
  9077. Related Words: UNMARKFCLOSE  
  9078. MARKFREEBLOCK   ( memory-block -- ) 
  9079. MARKFREEBLOCK places the memory-block on a list of memory-blocks that will be closed if the system executes QUIT .   
  9080. This mechanism allows an application to automatically 'clean-up' its resources in both of the two possible paths most programs may take... normal completion or an irrecoverable error abort.   
  9081. Note that if the application terminates normally, it should clear this AUTO-FREE status for the memory-block by executing UNMARKFREEBLOCK for each memory-block it had previously marked.   
  9082. 0 1024 ALLOCBLOCK ?DUP  \ allocate 1K, did it allocate? 
  9083. IF DUP MYMEM !     \ yes, save pointer in my variable 
  9084.     MARKFREEBLOCK   \ set it to auto-free at quit 
  9085.     RUN-MY-PROGRAM  \ do whatever I want to do with the mem 
  9086.     MYMEM @ DUP     \ need to do TWO thing to the pointer...  
  9087.     UNMARKFREEBLOCK \ remove it from the QUIT list...  
  9088.     FREEBLOCK       \ and free the memory 
  9089. ELSE ." can't allocate memory " 
  9090. THEN 
  9091. Related Words: UNMARKFREEBLOCK  
  9092. MATCH? ( addr1 count1  addr2 count2 -- addr | FALSE ) 
  9093. Search for string2 within a larger string1, leaving the address within string1 that matches if found, or FALSE if not found.   
  9094. By setting contents of the USER variable MCASE-SENSITIVE true, a programmer can make the search be case-sensitive.   
  9095. : LOOKFOR ( $string -- addr ) 
  9096.     COUNT  ( get address and count of big string ) 
  9097.     " RAIN" COUNT MATCH? ; 
  9098. " THE RAIN IN SPAIN" LOOKFOR 
  9099. Related Words: TEXT=? $= MCASE-SENSITIVE COMPARE  
  9100.  MATHFFP?
  9101. MATHFFP_LIB
  9102. MATHFFP_NAME
  9103. Standards: JForth unique.   
  9104. These are used to manage to MATHFFP library.   
  9105.  MATHIEEEDOUBBAS?
  9106. MATHIEEEDOUBBAS_LIB
  9107. MATHIEEEDOUBBAS_NAME
  9108. Standards: JForth unique.   
  9109. These are used to manage the MATHIEEEDOUBBAS library.  See :LIBRARY.   
  9110.  MATHIEEESINGBAS?
  9111. MATHIEEESINGBAS_LIB
  9112. MATHIEEESINGBAS_NAME
  9113. Standards: JForth unique  
  9114. These are used to manage the MATHIEEESINGBAS library.  See :LIBRARY.   
  9115.  MATHTRANS?
  9116. MATHTRANS_LIB
  9117. MATHTRANS_NAME
  9118. Standards: JForth unique.   
  9119. These are used to manage the MATHTRANS library.  See :LIBRARY.   
  9120. MAX  ( n1 n2 -- n1 | n2 ) 
  9121. Compare the top two items on the stack, leave the largest signed value. You can use MIN and MAX to clip a value to a boundary.   
  9122. 23 7 MAX . ( print 23 ) 
  9123. ( make sure x not negative ) 
  9124. CALC.X ( -- x ) 0 MAX SQRT 
  9125. Related Words: MIN >  
  9126. MAX-INLINE   max inline 
  9127. This is a USER-variable examined by the compiler when it is about to compile a reference to a word that may be either INLINE or CALLED.  See (CFA,) .  If a referenced word is defined as BOTH, and its size is over MAX-INLINE then a subroutine call to that word will be compiled.  Otherwise it will be compiled as an inline macro.  You can use this word to make trade offs between memory usage and speed.  The higher MAX-INLINE is, the faster the code that is produced.  Generally varying MAX-INLINE from 6-256 results in a size difference of 5-20% .   
  9128. 16 MAX-INLINE ! 
  9129. Related Words: (CFA,) BOTH INLINE  
  9130. MAXVOCS max vocs 
  9131. This is a system CONSTANT, equal to the maximum number of VOCABULARIES that may be defined.   
  9132. Standards: JForth unique  
  9133. Related Words: VOCABULARY  
  9134. MCASE-SENSITIVE ( -- addr ) 
  9135. This variable is used to control the case sensitivity of TEXT=?, a primitive for MATCH?.   
  9136. See MATCH?  TEXT=?.   
  9137. MEASURE   ( <forth> -- ) 
  9138. Measure the time it takes to execute the following code and print the time.  This is handy for benchmarking code.  Use BENCH if you are benchmarking things in a loop and need to subtract the overhead time.   
  9139. \ Time how long it takes to compile it.  
  9140. MEASURE INCLUDE JU:DEBUGGER 
  9141.  MEMF_CHIP
  9142. MEMF_CLEAR
  9143. MEMF_FAST
  9144. MEMF_PUBLIC
  9145. AMIGA Constants. See ALLOCBLOCK.   
  9146. MENU.SETUP   ( 0name menu# menu-addr -- ) 
  9147. Initialize an Intuition Menu structure to reasonable defaults.  See the chapter on Amiga Menus.   
  9148. Related Words: EZMENU  
  9149. MIN    ( n1 n2 -- n1 | n2 ) 
  9150. Compares the top two stack values n1 and n2, leaving the smallest value.   
  9151. ( limit your deduction ) 
  9152. TAX-DEDUCTION @  MAX-ALLOWED @  MIN 
  9153. Related Words: MAX   
  9154. MOD   ( n1 n2 -- rem )   "mod" or "modulus" 
  9155. Leaves signed remainder REM on top of the stack after dividing N1 by N2.   
  9156. 13 5 MOD . ( print 3 ) 
  9157. Related Words:  
  9158. /MOD */MOD M/MOD 
  9159.  MODE_NEWFILE   MODE_OLDFILE
  9160. See FOPEN.   
  9161. MOVE   ( addr1 addr2 u -- )  
  9162. Copies U bytes in memory starting at address ADDR1 to memory starting at address ADDR2.   
  9163. MOVE will decide whether to copy from top to bottom, or vice versa, if the destination overlaps the source area.  This will avoid the problem of data overwriting itself which can happen with CMOVE. 
  9164. MOVE is also an optimized data transfer; under the right conditions, it will move data in excess of 1 megabyte/second on a standard Amiga 500.  
  9165. Related Words: CMOVE CMOVE> WMOVE  
  9166. MSEC   ( #milliseconds -- ) 
  9167. Delay for approximately that many milliseconds.  Delays over 20 milliseconds use the Amiga Delay() function.  Delays less than 20 milliseconds have to use software timing and can err in accuracy.  Do not use this where extreme accuracy is required.  From file JU:MSEC.   
  9168. 1000 MSEC  ( wait one second ) 
  9169. MYDSP  my d s p 
  9170. This USER-variable is not implemented in JForth V2.0, but is reserved for future use.   
  9171. MYRP   my r p 
  9172. This USER-variable is not implemented in JForth V2.0, but is reserved for future use.   
  9173. MYTOS  ( -- addr )  "my tos" 
  9174. This USER-variable is not implemented in JForth V2.0, but is reserved for future use.   
  9175. N>LINK   ( nfa -- lfa )   "n to link" 
  9176. Used to derive the link-field-address of a dictionary header from the name-field-address.   
  9177. Related Words: LINK>  >LINK ' >NAME  
  9178. N>TEXT   ( n -- addr count )   "n to text" 
  9179. Convert a number to it's text equivalent in the current base.  Like . except it doesn't type out the characters.  This is useful when you want to write formatted files or draw numbers graphically.   
  9180. GR.INIT GR.OPENTEST 20 30 GR.MOVE 
  9181. 1234 N>TEXT GR.TYPE  ( draw number ) 
  9182. Related Words: # . #DIGITS BASE EMIT LOGTO  
  9183. NAME>   ( nfa -- cfa )   "name to" 
  9184. NAME> converts the name-field-address of a dictionary header to the code-field-address.  The code-field-address is that place in a standard dictionary entry that contains the executable code for that definition.   
  9185. ." The most recently compiled code is " 
  9186. LATEST DUP ID. NAME> DISM 
  9187. Related Words: >NAME '  
  9188. NEGATE   ( n -- -n ) 
  9189. NEGATE reverses the sign of N.   
  9190. 2 NEGATE .  ( prints -2 ) 
  9191. Related Words: DNEGATE  ABS XOR  
  9192. NEW 
  9193. ( -- )  
  9194. This word places MODE_NEWFILE in the user-variable FILEMODE.  When the next file is opened using FOPEN, it will now create a NEW file instead of opening an existing one.  See the chapter on File I/O.   
  9195. CAUTION: do not set the NEW mode, unless a call to FOPEN, $FOPEN, or 0FOPEN immediately follows.  Forgetting that NEW has been executed can result in the next file to be opened being inadvertently lost.  The word OLD reverts filemode to MODE_OLDFILE, as do both FOPEN operations.   
  9196. NEW FOPEN EMPTY-FILE 
  9197. Related Words: FOPEN $FOPEN OLD  
  9198. NEXTTASK 
  9199. This USER-variable is not implemented in JForth V2.0, but is reserved for future use.   
  9200. NFA  ( cfa -- nfa ) 
  9201. NFA has been renamed to >NAME to comply with the '83 standard.  If you want NFA load JU:MULTISTANDARD.   
  9202. NIP   ( a b -- b ) 
  9203. Remove second item from stack.  Equivalent to, but faster than,   SWAP DROP.
  9204. Related Words: SWAP DROP  
  9205. NO@  ( -- ) 
  9206. Set the mode for local variable to not automatically  fetch their values. They will leave their address instead.  See the section on Local Variables.   
  9207. Related Words: { } YES@  
  9208. NO-COMMAS   ( -- )  
  9209. Turn off the use of commas when formatting numbers for output, by storing a FALSE in the user-variable (COMMAS).   
  9210. Related Words: COMMAS  (COMMAS)  
  9211. NOCASE ( -- n ) 
  9212. NOCASE is a CONSTANT used to determine the desired characteristics of output ASCII case .  See OUTPUT-CASE.   
  9213. NOCONSOLE   ( -- var-addr )
  9214. See the chapter on CLONE.   
  9215. NOOP   ( -- )   "no op" 
  9216. This is an empty compiled definition, generally useful for disabling deferred words that have no effect on the stack.   
  9217. DEFER MY-VECTOR    ' NOOP IS MY-VECTOR 
  9218. NOT   ( flag -- logically-opposite-flag ) 
  9219. Reverse the logic of the flag on the stack.  This word acts to change a non-zero value to zero, and a zero to -1.  This is a synonym for 0= .   
  9220. NOTE: this is a departure from the '83 standard, which is to perform a 1's-complement operation on the flag.  Load JU:MULTISTANDARD if you need the standard NOT .   
  9221. BEGIN  MONEY-GONE? NOT 
  9222. WHILE  SPEND-MORE 
  9223. REPEAT 
  9224. Related Words: 0= COMP  
  9225. NUMBER   ( $addr -- d ) 
  9226. Converts a character string starting at address $ADDR into a double cell signed number using the value in BASE.  The ADDR parameter points to a length byte.  NUMBER is deferred and is changed when the floating point system is active.   
  9227. If a decimal point is present in the string, the value in DPL will reflect the number of digits following it; otherwise DPL contains -1.   
  9228. If the string cannot be converted, it is printed on the standard output device, and the ERROR exit is taken.   
  9229. : ADDONE ( -- , convert add & print ) 
  9230.     BL WORD NUMBER  ( -- d ) 
  9231.     DROP 1+ . ; 
  9232. ADDONE 1234  ( prints 1235 ) 
  9233. Related Words: ERROR  NUMBER?  CONVERT  DPL  
  9234. NUMBER?   ( $addr -- d true | false ) 
  9235. Attempt to convert the string at address $ADDR to a number, using the current value of BASE. If successful , return the double number and true; otherwise return false.   
  9236. Standards: JForth unique.   
  9237. Related Words: NUMBER  CONVERT  
  9238. OB.ARRAY   ( <name> -- ) 
  9239. Create an instance, or object, of the class OB.ARRAY.  This is a powerful type of array data structure.  See the chapter on ODE.   
  9240. OB.ELMNTS   ( <name> -- ) 
  9241. Create an instance, or object, of the class OB.ELMNTS.  This is a powerful type of multidimensional array data structure.  See the chapter on ODE.   
  9242. OB.STATS?   ( <member> -- offset #bytes ) 
  9243. Returns information about a structure member.  This information is used by the compiler to compile proper references to Amiga 'C' structures.   
  9244. GETMODULE INCLUDES 
  9245. OB.STATS? NW_WIDTH .S 
  9246. OBJECT   ( <name> -- ) 
  9247. Create a basic OBJECT.  OBJECT is the root class from which all other ODE objects are derived.  See the chapter on ODE.   
  9248. ODE 
  9249. ODE is not an executable Forth word.  It stands for the Object Oriented Development System.  See the chapter on ODE.   
  9250. ODD!   ( n addr -- )   "odd store" 
  9251. Store a cell N at an odd or even address ADDR . Uses sequential BYTE accesses.   
  9252. Normally not needed, since all JForth cell addresses are word aligned, but must be used if your code has a possibility of doing LONG references to odd addresses.  The 68000 will generate an address error if you access word or long data at an odd address.   
  9253. Standards: JForth unique. 68000 unique.  68020 will be able to use @ . Existence and definition depend on the host CPU type.   
  9254. Related Words: @ ! D! D@ EVEN-UP ALIGN  
  9255. ODD@   ( addr -- n )   "odd fetch" 
  9256. Fetch a cell N from an odd or even address ADDR .  See comments under ODD! above.   
  9257. 71 ODD@ . ( won't crash ) 
  9258. Related Words: ODDW@ ODDW!  ODDD@ @ ! D! D@ EVEN-UP ALIGN   
  9259. ODDD!   ( d addr -- )   "odd d store" 
  9260. Store a double number at an odd or even address.  See comments under ODD! above.   
  9261. ODDD@   ( addr -- d )   "odd d fetch" 
  9262. Odd addressable D@ .  See comments under ODD! above.   
  9263. ODDW!   ( n addr -- ) 
  9264. Odd addressable W! See comments under ODD! above.   
  9265. ODDW@   ( addr -- n ) 
  9266. Odd addressable W@.  See comments under ODD! above.   
  9267. OF   ( value n -- ) 
  9268. Used in conditional statement with CASE .  See CASE .   
  9269. OFF   ( var-address -- ) 
  9270. Set the contents of the given address off.   
  9271. FILEHEADERS OFF 
  9272. Related Words: ON !  
  9273.  OFFSET_BEGINNING
  9274. OFFSET_CURRENT
  9275. OFFSET_END
  9276. ( -- n1 )  
  9277. These  are  AMIGA  constants, used to specify the type of FSEEK operation to perform.  See FSEEK.   
  9278. OLD   ( -- ) 
  9279. This word places MODE_OLDFILE in the user-variable FILEMODE.  This will cause FOPEN to attempt to open an existing file.  See the chapter on File I/O.   
  9280. OLD FOPEN AN-EXISTING-FILE 
  9281. Related Words: FOPEN 0FOPEN NEW  
  9282. ON   ( var-address -- ) 
  9283. Set the contents of the given address to TRUE (-1).   
  9284. VARIABLE DO-WINDOWS 
  9285. DO-WINDOWS ON  ( set TRUE ) 
  9286. Related Words: OFF !  
  9287. ONLY   ( -- ) 
  9288. Remove all vocabularies from the context stack except ROOT.  This is used to reset the vocabulary search path.  See the section on Forth Vocabularies.   
  9289. ONLY FORTH  ( set back to default ) 
  9290. Related Words: ALSO PREVIOUS FORTH ORDER  
  9291. OPENFV   ( var-addr -- memory-block ) 
  9292. OPENFV is used to allocate a 1024-byte memory area that can later be used for a sequential virtual-buffer for fast file I/O.  See the chapter on File I/O.   
  9293. OR   ( n1 n2 -- n3 ) 
  9294. Logical bit by bit or'ing of n1 and n2 .  Result n3 is on top of stack . If a bit is on in either N1 OR N2 then the same bit will be on in N3.   
  9295. BINARY 0011 1001 OR .    ( print 1011 ) 
  9296. ( do something if key hit or input out of range ) 
  9297. 100 >  ?TERMINAL  OR IF 
  9298. Related Words: NOT AND XOR IF  
  9299. ORDER   ( -- ) 
  9300. Display the order of vocabularies that will be searched by the Forth compiler.  It also shows the CONTEXT vocabulary which is where newly defined words will go.  See the section on Forth Vocabularies.   
  9301. OUT   ( -- addr ) 
  9302. User variable that contains a value incremented by EMIT, OUT indicates the column number that the cursor is currently in.  OUT is reset by CR .   
  9303. : GOTAB  ( -- , move to next tab )  
  9304.     OUT @ 8 MOD 
  9305.     8 SWAP - SPACES ; 
  9306. Related Words: EMIT CR CR? >NEWLINE +OUT  
  9307. OUTBUF   ( -- addr ) 
  9308. Returns the address of the output buffer being used by the FAST I/O mode. See FAST.   
  9309. OUTPUT-CASE   ( -- var-addr ) 
  9310. This is a USER-variable that may be used to force characters that are EMITed to one of the desired output forms:  
  9311. 1) NOCASE  - output in mixed case, no conversion (default)  
  9312. 2) LOCASE  - output appears in lower case only.   
  9313. 3) HICASE  - output appears in upper case only.   
  9314. HICASE OUTPUT-CASE ! 
  9315. ." Hello Fred" CR 
  9316. OVER  ( a b -- a b a ) 
  9317. Copy second item on stack to top. Leapfrog.   
  9318. 11 22 OVER .S  ( print 11 22 11 ) 
  9319. Related Words: DUP ROT  
  9320. PAD   ( -- addr ) 
  9321. PAD returns the address of a temporary work area.  PAD is defined as HERE + 128.  Be careful HERE doesn't move when you are using PAD because it will move too.  Immediate strings are stored at PAD.  Numeric strings are built just below PAD.  PAD extends up until it runs into the data stack area.   
  9322. " Hello" . PAD .  
  9323. Related Words: #K HERE SP@  
  9324. PARSE   ( char -- addr count ) 
  9325. PARSE uses the value of >IN as an index into the address and count returned by SOURCE, parsing from that location until either  CHAR  is found or the string is exhausted.   
  9326. PARSE returns the address ADDR of where it started looking and the COUNT of the characters until CHAR was found.   
  9327. PARSE does not skip over leading occurrences of CHAR.  It returns even if the first character checked is  CHAR .   
  9328. : PS" ( -- , like ." ) 
  9329.    ASCII " PARSE TYPE ; 
  9330. 20 5 - PS" Answer = " . CR 
  9331. ( print   Answer = 15 ) 
  9332. Related Words: /STRING  SOURCE SKIP SCAN WORD QUERY  
  9333. PARSE-WORD  ( char -- addr count ) 
  9334. PARSE-WORD is just like PARSE except it will skip over skip over leading delimeters.  IF the first character it finds equals  char , it will continue checking until a non-delimiter is found.  It will then again look for a delimiter, after which it will return.   
  9335. Related Words: /STRING  SOURCE  
  9336. PICK  ( ... v2 v1 v0 M -- ... v2 v1 v0 vM ) 
  9337. Create a copy of value number M, replacing M on the stack.  Value number 0 is the value immediately below the PICK index.   
  9338. !!! WARNING !!! - This '83 version of PICK differs from old standard versions of PICK.  In old versions, the top value was value number 1 not 0 .  Please see the MULTISTANDARDS facility for access to different versions of PICK .  The following code shows the equivalent of doing a DUP.   
  9339. OLD WAY     vs    NEW WAY 
  9340. 1 PICK            0 PICK 
  9341. Standards: '79 '83  
  9342. 33 45 66 87   2 PICK .  ( print 45 ) 
  9343. Related Words: RPICK XPICK ROT  
  9344. PLACE   ( source-address count $dest-addr -- )     
  9345. PLACE is used to move a string from one address to another.  If the user-variable MAKEUCASE is non-zero, it will convert the string to upper-case after the move.   
  9346. Instead of manipulating MAKEUCASE, the programmer may call LPLACE, which will not perform the conversion, allowing lower-case output.   
  9347. Standards: JForth unique  
  9348. CREATE SPAD 80 ALLOT   \ make string holder 
  9349. " Hello World" COUNT SPAD PLACE 
  9350. SPAD COUNT TYPE   \ print copied string 
  9351. Related Words: $MOVE MOVE COUNT  
  9352. PREVIOUS  ( -- ) 
  9353. Drops the vocabulary added to the context stack by ALSO.  This provides a way to unnest changes to the compiler search order.  See the section on Forth Vocabularies.   
  9354. ALSO MUSIC   \ search music vocab first 
  9355. INCLUDE COMPOSITION 
  9356. PREVIOUS     \ now back the way it was 
  9357. POP ( memblock -- n ) 
  9358. POP is used on a memory block that had been allocated via ALLOCBLOCK, and returns the cell just under that being pointed to by FREEBYTE, adjusting the FREEBYTE counter.   
  9359. POP, in conjunction with PUSH, allows memory of this type to be conveniently used as stacks.  Using the contents of the FREEBYTE field of a memblock, these words keep track of the  next free location.   
  9360. Note that, for efficiency , no error checking is performed by POP.  It is the responsibility of the calling program to insure data is present before trying to POP it.   
  9361. Standards:  JForth unique.   
  9362. \ Close a stack of files.  
  9363. MY-FILES @   DUP FREECELL 0  ( -- memblock #cells 0 ) 
  9364. DO   DUP POP ( -- memblock file-pointer ) FCLOSE 
  9365. LOOP DROP 
  9366. Related Words: PUSH ALLOCBLOCK FREEBYTE +STACK -STACK
  9367. POTGO?
  9368. POTGO_LIB
  9369. POTGO_NAME
  9370. These words are used to manage the POTGO Library.  See :LIBRARY.   
  9371. PRINTER.ON
  9372. Echo JForth output to both the screen and printer.  Uses $LOGTO to vector EMIT .
  9373. INCLUDE JU:LOGTO
  9374. PRINTER.ON   MAP   PRINTER.OFF  ( print MAP on printer )
  9375. If you want print a file on the printer, you can use the AmigaDOS copy command.
  9376. COPY  filename  PRT:
  9377. If you want to print a file with line numbers and proper page breaks, you can use the JForth Print Application.  See the appendix on the Clonable Applications.
  9378. PULLTIB   ( -- )   "pull t i b" 
  9379. PULLTIB restores the previous TIB environment that had been saved via PUSHTIB.   
  9380. PULLTIB causes the TIB, #TIB, >IN and FBLK to be restored.   
  9381. Standards: JForth unique  
  9382. PUSHTIB   QUERY INTERPRET  PULLTIB 
  9383. Related Words: PUSHTIB #TIB TIB  
  9384. PUSH   ( n memblock -- ) 
  9385. PUSH is used on a memory block that had been allocated via ALLOCBLOCK, and places N in the location being pointed to by the base address+FREEBYTE, adjusting FREEBYTE to the next available location.   
  9386. PUSH, in conjunction with POP, allows memory of this type to be conveniently used as stacks.   
  9387. Note that, for efficiency sake, no error checking is performed by PUSH.  It is the responsibility of the calling program to insure that room exists in the allocated memory space before PUSHing to that area.   
  9388. Standards:  JForth unique.   
  9389. ( -- file-pointer )  MY-FILES @  DUP FREEBYTE OVER SIZEMEM < 
  9390. IF   PUSH 
  9391. ELSE ." FILE-STACK FULL!  NO ROOM FOR ANOTHER PUSH!" QUIT 
  9392. THEN 
  9393. Related Words: FREEBYTE FREECELL SIZEMEM POP ALLOCBLOCK  
  9394. PUSHRELOC   ( rel-addr -- )   "push reloc" 
  9395. This creates a relocation entry for an address that requires relocation by the Amiga Loader as JForth is being loaded in from mass storage.   
  9396. Occasionally, in a large image, it is necessary to compile an absolute 32-bit address, referencing another part of JForth, within the body of a definition.   
  9397. This potentially could pose a problem, as programs cannot specify their destination when being loaded, and any absolute references will be invalid.   
  9398. JForth solves the problem by keeping a table of all addresses needing relocation.  To add to this table, just pass to PUSHRELOC the JForth-relative address of the location that contains the 32-bit reference.  Note that the location should be properly initialized with the correct 32-bit absolute address when PUSHRELOC is called.   
  9399. Standards:  Amiga unique  
  9400. VARIABLE IMAGE-BASE   0 >ABS IMAGE-BASE !  IMAGE-BASE PUSHRELOC
  9401.  
  9402. PUSHTIB   ( -- ) 
  9403. PUSHTIB saves information about the TIB and INTERPRET environment.  Input can then be redirected to a new level, then each environment restored by a corresponding call to PULLTIB.  
  9404. This technique is used in such nestable system words as INCLUDE and ?PAUSE.
  9405. PUSHTIB is nestable to a level of 16.
  9406. Standards:  JForth unique 
  9407. PUSHTIB   QUERY INTERPRET  PULLTIB 
  9408. Related Words: PULLTIB #TIB 
  9409. QUERY   ( -- ) 
  9410. QUERY will repeatedly receive characters from the keyboard, placing them in the TIB until a carriage return is entered.  Upon exiting, #TIB will contain the number of characters received, and >IN will be 0.  
  9411. Note that calling QUERY while a valid INTERPRET stream exists in the TIB will result in the loss of the remainder of the stream, unless PUSHTIB and PULLTIB are utilized before and after the QUERY operation and subsequent user processing.  
  9412. : GET-NUMBER ( -- d ) ." Input a number: " 
  9413.    QUERY  BL WORD NUMBER ; 
  9414. Related Words: EXPECT TIB >IN PUSHTIB PULLTIB  #TIB 
  9415. QUIT  ( -- , quit whatever and return to interpreter )
  9416. QUIT is a DEFERred word, whose default content in JForth is (QUIT).  When a program has sensed an irrecoverable error, QUIT is the function used to terminate program flow, and restart the system from a known point.  In a cloned application, QUIT will cause an exit from the program.  For more information specific to QUIT in the development environment, see (QUIT).  
  9417. 0< IF ." Error in this word!" QUIT THEN 
  9418. Related Words: INTERPRET ABORT CLONE 
  9419. GL -      Glossary
  9420.  
  9421.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  9422.  
  9423.     Glossary    GL -  
  9424.  
  9425.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  9426.  
  9427.  
  9428.  
  9429.  
  9430.  
  9431. R   ( -- n )   ( n --R-- n )  
  9432. Copies the top of the return stack onto the top of the data stack.  As this name has been superseded by R@, we do not recommend R.   
  9433. Standards: FIG ,  R@ in '79 and '83.   
  9434. Related Words: >R  R>  R@  
  9435. R#   ( -- addr )   "r sharp" 
  9436. R# is a USER-variable that is only applicable in the BLOCK environment.   
  9437. After the source file SCRED has been loaded, it is used to store the current cursor position (relative to the start of the BLOCK) in the supplied, FIG-like line editor.   
  9438. R# @ C/L /  ( leaves line# cursor is on ) 
  9439. Related Words: LOAD BLOCK Used by many words in line editor and SCRED.   
  9440. R>   ( -- n )    ( n --R-- )   "r from" 
  9441. Takes a value N off of the return stack and pushes it onto the data stack. WARNING Only remove thing from the return stack that you put there with >R .  Otherwise the subroutine return mechanism will fail.  The return stack is a handy place to temporarily store values.   
  9442. : UNDER1+  ( a b -- a+1 b ) 
  9443.     >r  ( save B ) 1+ r> ; 
  9444. Related Words: >R R@ RDROP  
  9445. R0   ( -- addr )   "r zero" 
  9446. USER variable containing the initial value for the return stack  pointer. This is used internally by JForth System Manager  
  9447. Related Words: RP!  
  9448. R@   ( -- n )   ( n --R-- n )   "r fetch" 
  9449. Copy top of return stack onto top of stack .   
  9450. Standards: '83 and '79 . FIG uses R  
  9451. : EXAMPLE ( -- )  5 >R R@ ( will be 5 ) RDROP ; 
  9452. Related Words: >R  R>  R  
  9453. RANDOM ( -- rnd )
  9454. Generate a 16 bit pseudo-random number using the linear congruential method.  This is in JU:RANDOM.  The sequence is based on the variable RAND-SEED.  
  9455. Related Words: CHOOSE
  9456. RANGEOF ( value low high -- value | )
  9457. Executes the following code up to an ENDOF, and drops the value, if the value falls within the given range.  The range includes LOW and HIGH.  See CASE.
  9458. RAWEXPECTECHO   ( -- var-addr )
  9459. See the chapter on CLONE.   
  9460. RDROP   ( -- )  ( n --R-- )   "r drop" 
  9461. Drop top item N off the return stack.  Only drop things you put there or the subroutine mechanism will fail.   
  9462. : EXAMPLE ( -- )  5 >R RDROP ;  ( won't crash )  
  9463. Related Words: DROP XRDROP >R R> R@  
  9464. READLINE   "read line" 
  9465. ( file-pointer var-addr addr maxlen -- addr #read | addr -1  if EOF )  
  9466. file-pointer  specifies the file to read.  
  9467. var-addr  holds the address of the virtual-buffer.  
  9468.   addr = the place in memory to place the data 
  9469. maxlen = maximum # characters to read 
  9470. READLINE is used to read the next line of a file into memory, stopping at the EOL character, or if the memory limit is reached.  The memory is read through a 1K sequential virtual-buffer that has been allocated via OPENFV .  See OPENFV .   
  9471. The memory address is passed through.  In addition, if not at end-of-file, the number of characters that were actually read is returned.  Otherwise a -1 is returned.  Note that an empty line will return 0, a valid line-length.   
  9472. Virtual memory areas allocated for reading should be closed via CLOSEFVREAD .   
  9473. See chapter on File I/O for more information.   
  9474. : NEXTLINE   ( -- flag , read and display next line ) 
  9475.     MY-FILE @  MY-BUFFER  PAD  1000  READ-LINE 
  9476.     ( -- addr n1 )   dup 0> 
  9477.     IF TYPE TRUE 
  9478.     ELSE 2DROP FALSE 
  9479.     THEN ; 
  9480. Related Words: OPENFV  LINESFILLV  CLOSEFVREAD FREAD  
  9481. RECURSE  ( -- ) 
  9482. Calls word currently being defined.  Recursion is powerful tool but must be used with caution.  The rules for recursion are: 
  9483. 1) Do NOT use global variables because they will be changed by recursive calls.  Use Local Variables instead.
  9484. 2) Provide a way to stop recursion.  Excessively deep recursion will overflow the return stack.
  9485. Here is an example of using recursion to calculate N factorial. N Factorial is defined as: 
  9486. N*(N-1)*(N-2)....*1
  9487. We can define it recursively as: 
  9488. FACT(N) = N * FACT(N-1)
  9489. FACT(1) = 1
  9490. Here is the Forth code.  If this is the first time you have used recursion, it will seem a little mind bending. LISP programmers do this stuff all the time. 
  9491. : FACT  ( N -- N-factorial )
  9492.     dup 1 >
  9493.     IF
  9494.         dup 1- recurse *
  9495.     THEN
  9496. ;
  9497. 4 FACT . \ should print 24
  9498. RECURSIVE ( -- ) 
  9499. This is not in the dictionary because it is so easy to define. When a word is being defined, it is SMUDGED so that if the compilation fails it can't be called.  By calling UNSMUDGE, we can allow a word to call itself.  Compare this example to the example under RECURSE. 
  9500. : RECURSIVE  ( -- ) unsmudge ; immediate
  9501.  
  9502. : FACT  ( N -- N-factorial )
  9503.     RECURSIVE  \ make this word recursive
  9504.     dup 1 >
  9505.     IF
  9506.         dup 1- FACT *  \ calls itself!
  9507.     THEN
  9508. ;
  9509. REDEF?   ( -- addr ) 
  9510. This user-variable is scanned by (CREATE) .  If a Forth word is redefined a message will be printed if this variable if TRUE.   
  9511. REDEF? OFF 
  9512. : FOO ; 
  9513. : FOO ;   ( NO message!) 
  9514. REPEAT   ( -- ) 
  9515. Used to terminate a BEGIN ... WHILE ... REPEAT conditional construct. Unconditionally branches to code following BEGIN.  See WHILE for example.   
  9516. For advanced users: REPEAT is actually an IMMEDIATE word that has the following stack diagram.   
  9517. ( addr-begin begin-flag waddr while-flag -- )  
  9518. addr-begin = address following BEGIN to branch to 
  9519. begin-flag = shows BEGIN started the loop 
  9520.      waddr = address of 0BRANCH offset created by WHILE 
  9521. while-flag = pairs checking signature for WHILE 
  9522. Related Words: BEGIN WHILE UNTIL IF ELSE THEN DO LOOP  
  9523. RETURN   ( -- ) 
  9524. RETURN causes an immediate exit from the the current colon definition, even from within nested DO LOOP's .  Like the other control structures, IF ELSE LOOP etc... , It has an immediate part and a run time part.  RETURN figures out the LOOP nest level at compile time, then compiles the appropriate number of return stack items to drop.  If used outside any LOOP structures, RETURN compiles EXIT .  The run time action is to exit the function when executed.   
  9525. Run time:  
  9526.   Stack: ( -- )  
  9527.   Return stack: ( return-address loop-parameters... --R--)  
  9528. Compile time 
  9529.   Stack: ( -- )  
  9530.   Return stack: ( --R-- )  
  9531.  
  9532.        : EXAMPLE   ( -- )  10 0  
  9533.            DO  100 0  
  9534.                DO  I . ." about to return, bye" RETURN 
  9535.                ." won't get here" 
  9536.                LOOP ." won't ever print this"  
  9537.            LOOP  ." Also won't print this" ; 
  9538.            ( different from LEAVE) 
  9539. Related Words: ?RETURN EXIT ?EXIT LEAVE  
  9540. REVERTVOC   ( -- addr ) 
  9541. REVERTVOC is a USER-variable that is examined by  :  "colon".  If found true, it will, at the very beginning of the definition, change the vocabulary that will be searched to the CURRENT vocabulary.  The default state of REVERTVOC is FALSE.  REVERTVOC has been provided for compatibility with older vocabulary systems.   
  9542. Related Words: : VOCABULARY DEFINITIONS ORDER  
  9543. ROOT   ( -- )  
  9544. ROOT is the root vocabulary of JForth.  It will always be searched, even if the word ONLY was used.  See the section on Vocabulary for more information.   
  9545. Standard: '83 experimental proposal.   
  9546. Related Words: VOCABULARY ORDER VOCS   
  9547. ROT   ( a b c -- b c a ) 
  9548. Rotates the third item to the top of the stack.   
  9549. 11 22 33 ROT . ( prints 11 ) 
  9550. Related Words: SWAP DUP OVER PICK >R R>  
  9551. RP!  r p store 
  9552. RP! has two different meanings, based on the standard you are using.   
  9553. Standards: FIG and 79  (JForth default) ...   
  9554. ( -- )   
  9555. Initializes the return stack pointer to the address contained in R0 .  Used in COLD and QUIT .   
  9556. '83 (available from JU:MULTISTANDARD file)  
  9557. ( addr -- )  
  9558. Sets the return stack pointer to the addr on the data stack.   
  9559. Related Words: R0 COLD QUIT  
  9560. RP@   ( -- addr )   "r p fetch" 
  9561. RP@ pushes the return stack pointer address on top of the stack .   
  9562. RPICK    ( n -- rval-n )  
  9563. This is the return stack equivalent of PICK. RPICK uses the value N on the stack to copy the contents of cell number N out from the return stack and push the value on top of the stack . This is the only way to access items deep down on the return stack .  This is zero based so a 0 RPICK is equivalent to an R@ .  RPICK is very fast and efficient, compared to using multiple calls to R> .   
  9564. : EXAMPLE ( -- ) 
  9565.     5 >R 6 >R 7 >R 2 RPICK . ( 5 ) 3 XRDROP ; 
  9566. S->D   ( n -- d )   "s to d"  "single to double" 
  9567. S->D sign extends a 32 bit value N into a 64 bit double number D .  This means the MSB of N is duplicated through the upper half of D .   
  9568. -23 S->D D.  ( prints -23) 
  9569. Related Words: W->S  B->S  
  9570. S0   ( -- addr )   "s zero" 
  9571. S0 is a user variable containing the initial value of the stack pointer.   
  9572. Related Words: SP@ 0SP DEPTH R0  
  9573. SAVE-FORTH   ( <filename> -- ) 
  9574. Save the current JForth dictionary in a file that can be executed later.   
  9575. This yields two practical uses in the JForth development cycle:  
  9576. Useful utilities and in general, any program may be saved in compiled form, and therefore almost instantly  brought up .  This will prove valuable, as you can save a compiled image with just the routines you've tailored for developing and debugging your application.   
  9577. SAVE-FORTH is a vital part of the mechanism for expanding dictionary size. As your program grows in size, you may receive the "insufficient dictionary available" message.  The following procedure lists the steps for increasing your JForth image size:  
  9578. 1) Set the #K variable...it tells SAVE-FORTH how large an image to save. In our example, we simply increment #K by 20 with +! ...   
  9579. 20 #K +! 
  9580. Our new dictionary will be   20 X 1K (1K=1024)  or 20,480 bytes larger. Note: you can also place the absolute value for size in #K ... if it contained 100 , we could type:  
  9581. 120 #K ! 
  9582. This would have the same result.   
  9583. 2) Save the image to the disk, using your own filename:  
  9584. SAVE-FORTH MYFORTH 
  9585. NOTE: if #K holds 120, you will need slightly more than 120K of disk area (about 5% more).   
  9586. 3) Exit JForth, returning to the CLI with:  
  9587. BYE 
  9588. 4) From the CLI, run the image you just created with:  
  9589. RUN MYFORTH 
  9590. JForth will once again appear, (with the same words.)  The only difference will be the larger dictionary area.  Of course, you are using that much more Amiga memory now.  Note: if AmigaDOS says that you don't have enough memory to run your new image, try rebooting the system...this recovers any fragmented memory.   
  9591. Trivia:  By setting #K to less than the current HERE  (0 is a convenient number), SAVE-FORTH will create a minimum-sized image, occupying as little disk space as possible.  This image however, will have an available dictionary size less than 2K when later booted.  This could be useful for saving complete applications that you plan to use without adding much to their dictionary.   
  9592. Standards:  JForth unique  
  9593. Related Words: #K #U MAP  
  9594. SAVE-IMAGE   ( <wordname> <filename> [options] -- )
  9595. Save a cloned program to a file.  See the chapter on CLONE.   
  9596. SCAN    ( addr count char -- addr' count' ) 
  9597. addr = an address 
  9598. count = length to search 
  9599. char = an ASCII character  
  9600. addr' = address where char was found OR end+1 
  9601. count' = string length after matching char, 0 if not found 
  9602. SCAN the string at ADDR (that is COUNT bytes long) for CHAR.   
  9603. If found, return the address that matched and the REMAINING LENGTH of the string including the CHAR.  If not found, return the end-of-string+1 for ADDR' and a COUNT' of 0 .   
  9604. Standards: F83  
  9605. " A text string" COUNT ASCII r  SCAN  TYPE 
  9606. ( The above would print "ring" ) 
  9607. Related Words: SKIP PARSE PARSE-WORD COMPARE QUERY  
  9608. SCAN-ALL-VOCS   ( -- ) 
  9609. SCAN-ALL-VOCS is a JForth Unique generalized function for accessing  all the words in JForth.  Two deferred words are used.  WHEN-VOC-SCANNED  is executed when each vocabulary is scanned, WHEN-SCANNED is executed when each word is scanned.  By setting these words you can write systems that will process all of the words in the dictionary.  Please see the chapter on Vocabularies for more info.   
  9610. Related Words: WHEN-SCANNED WHEN-VOC-SCANNED SCAN-VOC SCAN-WORDS  
  9611. SCAN-WORDS   ( -- ) 
  9612. SCAN-WORDS is a JForth Unique generalized function for accessing  the words in the CONTEXT vocabulary. The deferred word WHEN-SCANNED is  executed when each word is scanned.   
  9613. Related Words: SCAN-VOC SCAN-ALL-VOCS WORDS CONTEXT  
  9614. SCAN-VOC   ( -- ) 
  9615. SCAN-VOC is a JForth Unique word used by SCAN-ALL-VOCS and SCAN-WORDS  to search a vocabulary. The deferred word WHEN-SCANNED is executed when each word is scanned.   
  9616. Related Words: WHEN-SCANNED WHEN-VOC-SCANNED SCAN-VOC SCAN-WORDS   
  9617. SEALMODULE   ( -- , <modulename> )
  9618. See the chapter on MODULES.   
  9619. SET-BIT   ( n bit# -- n' ) 
  9620. Set a specific bit in N.  Bit 0 is the LSB.   
  9621. 0 4 SET-BIT . ( 16 ) 
  9622. Related Words: CLR-BIT @BITS !BITS BIT-SET? BIT-CLR? OR AND XOR  
  9623. SHIFT    ( n shift-count -- n' )  
  9624. SHIFT n the number of bits indicated by shift-count, shifting in a zero as the new bit.  If shift-count is positive, the shift is to the left, otherwise  it is to the right.   
  9625. Useful, for example, when extracting or inserting bit fields.    
  9626. Standards:  83 suggested  
  9627. HEX 75  DUP  0F AND .  ( print 5) 
  9628. -4 SHIFT 0F AND .      ( print 7) 
  9629. Related Words: ASHIFT 2* 2/  
  9630. SHOWME   ( -- , <wordname> )
  9631. See the chapter on CLONE.   
  9632. SIGN   ( sign dbl -- dbl )   
  9633. If 'sign' is negative , add a minus sign to the output string.  The double number 'dbl' is not affected.  Used in numeric conversion.   
  9634. Standard: FIG.  In '83 ( n -- ).   
  9635. : N>TEXT  ( N -- addr count , signed number to text ) 
  9636.     S->D   SWAP   OVER  DABS 
  9637.     <#  #S  SIGN  #> ; 
  9638. -234 N>TEXT TYPE 
  9639. Related Words: HOLD # #S  
  9640. SIZEMEM   ( memory-block -- allocated-size ) 
  9641. Given the address of a memory-block that had been acquired via ALLOCBLOCK, return the size of the allocated block.  See chapter on Memory Management.   
  9642. MY-MEM @ SIZEMEM  ( -- size ) 
  9643. Related Words: ALLOCBLOCK  FREEBYTE  FREEBYTEA  FREEBLOCK  
  9644. SKIP   ( addr count char -- addr' count' ) 
  9645. addr = an address 
  9646. count = length to search 
  9647. char = an ASCII character  
  9648. addr' = address of 1st char that didn't match OR end+1 
  9649. count' = string length after non-matching char,  
  9650.        0 if entire string matches 
  9651. Remove leading characters from a string.   
  9652. Scan through the string at ADDR (that is COUNT bytes long) for CHAR, SKIPping leading occurrences until a non-matching character is found, or the end of the string.  If a non-matching character is found, return its address and the REMAINING LENGTH of the string.  If the entire string matches, return the end-of-string+1 for addr' and a count' of 0 .   
  9653. Standards: F83  
  9654. "     Finally a word!" COUNT BL SKIP  TYPE 
  9655. ( Don't type out leading spaces!) 
  9656. Related Words: SCAN PARSE PARSE-WORD COMPARE FIND  
  9657. SKIP-WORD 
  9658. SKIP-WORD causes the next pass through WORD or FILEWORD to ignore the input stream, accepting instead the existing text at HERE. 
  9659. : $CREATE ( $name -- , create a word whose name is on the stack )
  9660.     HERE $MOVE
  9661.     SKIP-WORD CREATE
  9662. ;
  9663. " MYDATA" $CREATE 234 ,
  9664. MYDATA @ .
  9665. Related Words: WORD  LWORD  FILEWORD UNWORD $FOPEN  
  9666. SLOW   ( -- )  
  9667. SLOW reverts the EMIT I/O to a conventional single-character scheme. JForth default I/O technique is line-buffered, see FAST.  In SLOW mode, emit will output each character as soon as it it is called.  This might be handy in debugging, continuously updated displays, etc.   
  9668. You may want to use FLUSHEMIT to force output in FAST mode instead of using SLOW.   
  9669. Standard: JForth unique .   
  9670. Related Words: (EMIT) (KEY)  FAST EMIT TYPE  
  9671. SMUDGE   ( -- )  
  9672. Mark the LATEST definition so that FIND will be unable to locate it. SMUDGE means to hide or conceal the latest definition .  SMUDGE is used in : and CODE and some other defining words to make sure an incomplete definition is not accidentally compiled or executed.   
  9673. Hashing may cause unpredictable results with SMUDGE , see HASH.OFF.   
  9674. Standards: FIG and  '79 use SMUDGE but they TOGGLE the smudge state, JForth sets it.  '83 systems use HIDE .   
  9675. VARIABLE BAD-MAKE 
  9676. : RISKY-WORD  ( -- flag , true if fails ) 
  9677.     bad-make @ ; 
  9678. : MAKEWORD 
  9679.     CREATE  SMUDGE ( Make unFINDable ) 
  9680.         risky-word abort" Couldn't MAKEWORD!" 
  9681.         UNSMUDGE   ( Make FINDable if survived RISKY-WORD) 
  9682.     DOES> .  
  9683. MAKEWORD OKWORD 
  9684. OKWORD    ( Will be found!) 
  9685. TRUE BAD-MAKE !  MAKEWORD BADWORD   ( Creation fails) 
  9686. BADWORD   ( Won't be found!) 
  9687. Related Words: UNSMUDGE REVEAL FIND CODE :  
  9688. SOURCE   ( -- addr count ) 
  9689. This is a DEFERred word; by default it executes (SOURCE).   
  9690. SOURCE is used by PARSE and PARSE-WORD to return the address and length of the available input stream.  (SOURCE) normally returns the TIB start and the contents of #TIB .   
  9691. Related Words: PARSE  PARSE-WORD  IS  WHAT'S TIB #TIB QUERY WORD  
  9692. SP!   "s p store" 
  9693. SP! has two different meanings, based on the standard you are using.   
  9694. FIG and '79  (JForth default) ...   
  9695. ( -- )   
  9696. Initializes the data stack pointer to the address contained in S0 .  Used in COLD and ERROR .   
  9697. '83 (available from JU:MULTISTANDARDS file)   
  9698. ( addr -- )  
  9699. Sets the data stack pointer to the addr on the data stack.  Use 0SP in place of the old style SP! .   
  9700. Related Words: 0SP SP@ S0 COLD  
  9701. SP@   ( -- addr )   "s p fetch" 
  9702. In a traditional Forth this is the address of TOS , the Top Of Stack.  In JForth, however, TOS is cached in register D7 inside the 68000.  It has no "address".  SP@ , then, actually returns the address of the SECOND item on the data stack in JForth.   
  9703. Try to avoid using SP@ , use PICK and DEPTH if you can.   
  9704. Related Words: RP@ DEPTH S0  
  9705. SPACE   ( -- ) 
  9706. Outputs an ASCII space, 20 hex, to the current EMIT device.   
  9707. Related Words: SPACES EMIT BL ASCII  
  9708. SPACES   ( n -- )  
  9709. Prints N spaces on the standard EMIT device . Ascii space = 20 hex .   
  9710. Related Words: SPACE EMIT TYPE  
  9711. SPAN   ( -- addr ) 
  9712. SPAN is a user-variable that is set to the number of characters last read in by EXPECT.   
  9713. : GET$ ( -- $string , input string ) 
  9714.     PAD 1+ 120 EXPECT ( place characters at PAD+1) 
  9715.     SPAN @ PAD C!     ( update byte count at PAD) 
  9716.     PAD ; 
  9717. Related Words: EXPECT QUERY  
  9718. SPARE   ( -- addr ) 
  9719. Literally a spare USER variable for temporary use by any program .   
  9720. FOPEN RAM:TEMP    SPARE !   ( handy place) 
  9721. Related Words: USER PAD >R  
  9722. SPEAK   ( $string -- ) 
  9723. Translate string to phonemes and speak them.  This uses the Amiga Narrator device.  Make sure you have the volume up.  Check out JD:DEMO_SPEAK for examples.   
  9724. INCLUDE? SPEAK JU:SPEAK 
  9725. SPEAK.INIT  ( -- , allocate I/O request block ) 
  9726. " Greeting Earthlings!" SPEAK  ( etc. ) 
  9727. " We come in pea  AAayaueahh!" SPEAK 
  9728. SPEAK.TERM  ( deallocate when through 
  9729. SQRT   ( N -- N**1/2 )   "square root" 
  9730. Take the integer square root of N.  Truncates answer.  You can scale N by 10,000 to get two "decimal places" of accuracy.   
  9731. INCLUDE? SQRT JU:SQRT 
  9732. 49 SQRT .   ( prints 7 ) 
  9733. STACKSIZE   ( -- var-addr )
  9734. See the chapter on CLONE.   
  9735. STATE   ( -- addr )  
  9736. A user variable used by INTERPRET, reflecting the state of the interpreter.   
  9737. The JForth interpreter may be in one of two states;  
  9738. 1) If STATE = zero, the interpreter is in INTERPRET Mode, executing words as they are parsed from the input stream.   
  9739. 2) If STATE = non-zero, the interpreter is in COMPILE Mode, compiling words as they are parsed from the input stream.   
  9740. Standards: '79, '83, In FIG 0 means system is compiling .   
  9741. : NAMEOF ( <word> -- nfa ) 
  9742.     BL WORD FIND   ( search dictionary ) 
  9743.     IF  >NAME STATE @  ( compiling mode? ) 
  9744.         IF [COMPILE] LITERAL  ( save in dictionary ) 
  9745.         THEN 
  9746.     ELSE COUNT TYPE ."  not found" 
  9747.     THEN 
  9748. ; IMMEDIATE 
  9749. NAMEOF SWAP ID.  
  9750. : FOO NAMEOF SWAP ID. ; ( compile SWAP's NFA as LITERAL ) 
  9751. FOO       ( print "SWAP" ) 
  9752. Related Words: INTERPRETING? COMPILING? [ ]  
  9753. STATS   ( -- )
  9754. See the chapter on CLONE.   
  9755. SWAP   ( a b -- b a ) 
  9756. Exchange top two stack items.   
  9757. 23 56 .S 
  9758. SWAP .S 
  9759. SWAP .S 
  9760. TASK   ( -- )  
  9761. TASK is an empty definition, below which resides the JForth Kernal (that part of JForth which can not be VIEWed or re-generated by the programmer).   
  9762. The source code for the JForth system is provided for all words above TASK, and the system can be regenerated from this point from the JF: directory on the EXTRAS disk.   
  9763. TEMPBUFF   ( -- addr ) 
  9764. TEMPBUFF is a user-variable, provided as a convenience for the programmer.   
  9765. The programmer may allocate a virtual-buffer via OPENFV, and place the resultant address in TEMPBUFF .   
  9766. Subsequently, the programmer may access file-virtual words that directly access TEMPBUFF, providing simple stack diagrams (they don't require the buffer or a variable address parameter).  The only such word provided is TEMPF, ; the programmer may easily add more.   
  9767. Note: TEMPBUFF usage is non-reentrant;  you must save its' contents if you call another word that will use it.   
  9768. Standard: JForth unique  
  9769. Related Words: TEMPFILE  TEMPF, OPENFV  
  9770. TEMPF,   ( n -- )   "temp f comma" 
  9771. This word writes the 32 bit value N to the file whose file-pointer is contained in TEMPFILE.   
  9772. The write operation will be done through a virtual-buffer, opened with OPENFV, whose address is contained in TEMPBUFF.   
  9773. NOTE: TEMPF, usage is non-reentrant.  You must save the contents of TEMPFILE and TEMPBUFF if you call another word that will also need it.   
  9774. Standard: JForth unique  
  9775. Related Words: TEMPBUFF  TEMPFILE  OPENFV  CLOSEFVWRITE  
  9776. TEMPFILE   ( -- addr ) 
  9777. TEMPFILE is a user-variable, provided as a convenience for the programmer.   
  9778. The programmer may open a file via FOPEN or (FOPEN), and place the resultant file-pointer in TEMPFILE.   
  9779. Subsequently, the programmer may access file-operation words that directly access TEMPFILE, providing simple stack diagrams (they don't require the file-pointer parameter).  The only such word provided is TEMPF, ; the programmer may easily add more.   
  9780. NOTE: TEMPFILE usage is non-reentrant.  You must save its contents if you call another word that will use it.   
  9781. Standard: JForth unique  
  9782. Related Words: TEMPBUFF  TEMPF,  
  9783. TEXT=?   ( addr1 count addr2 -- flag ) 
  9784. Compare two strings, each count bytes long, return a TRUE if they match, FALSE otherwise.   
  9785. TEXT=? will perform a case-sensitive compare if the value of MCASE-SENSITIVE is non-zero; otherwise the compare will be performed ignoring ASCII case (JForth default condition).   
  9786. : FROG=?  ( $word --flag )
  9787.     count 4 =
  9788.     IF " frog" count swap text=?
  9789.     ELSE drop false
  9790.     THEN
  9791. ;
  9792. " bird" frog=? .
  9793. " Frog" frog=? .
  9794. Standard: JForth unique  
  9795. Related Words: MATCH?  MCASE-SENSITIVE $= COMPARE PARSE SKIP SCAN  
  9796. THEN  ( -- ) 
  9797. Mark the end of an IF...THEN or an IF...ELSE...THEN conditional construct. See tutorial for more examples.   
  9798. : EXAMPLE  ( N -- ) 
  9799.     5 =  
  9800.     IF  ." It's a five! "  
  9801.     ELSE ." Why didn't you type in five? " 
  9802.     THEN 
  9803.     cr ." Thank you." ( executed in any case ) ;   
  9804. Related Words: IF ELSE BEGIN UNTIL WHILE REPEAT   
  9805. TIB   ( -- addr )   "terminal input buffer" 
  9806. TIB returns the memory area used for receiving and storing the input stream that will be INTERPRETed.   
  9807. TIB 100 TYPE  ( type this line plus previous stuff) 
  9808. Related Words: #TIB TIB0 SOURCE  
  9809.  TIMER? 
  9810. TIMER_LIB 
  9811. TIMER_NAME 
  9812. Internal operators to manage the TIMER library.  See :LIBRARY.   
  9813. TIMES   ( n -- ) 
  9814. Repeat the current command line N times.  TIMES should be placed at the the end of the command line.  TIMES can only be used from the keyboard.   
  9815. If the command-line is to repetitively operate on a number or set of numbers, they must exist on the stack prior to the beginning of the command-line.   
  9816. ." Hello! " CR 3 times 
  9817. ( This prints Hello! 3 times.) 
  9818. Related Words: >IN DO LOOP  
  9819. TOGGLE    ( addr mask -- ) 
  9820. Does an 8-bit EXCLUSIVE OR of byte at addr with the given mask.  Result is left in location addr.   
  9821. Standards: FIG  
  9822. " fred" COUNT OVER $ 20 TOGGLE TYPE 
  9823. ( change case of 'f' , print  Fred ) 
  9824. Related Words: XOR OR   
  9825. TRACKING   ( -- var-addr )
  9826. See the chapter on CLONE.   
  9827.  TRANSLATOR? 
  9828. TRANSLATOR_LIB 
  9829. TRANSLATOR_NAME 
  9830. Internal operators to manage the TRANSLATOR library.  See :LIBRARY.   
  9831. Standard: JForth internal .   
  9832. TRUE   ( -- true-flag ) 
  9833. A CONSTANT, equal to a boolean TRUE, or -1.   
  9834. Standards:  '83  (79 & FIG use a value of 1)  
  9835. Related Words: FALSE  
  9836. TUCK   ( a b -- b a b ) 
  9837. Duplicate and insert the top item on the stack below the second item.  This is a fast coded primitive, the high-level logical equivalent is:  
  9838. 11 22 SWAP OVER .S 
  9839.  
  9840. : NEW-DUMP  ( addr cnt -- ) 
  9841.     TUCK ( save count )   
  9842.     DUMP  .  ." bytes dumped" ; 
  9843. Related Words: OVER SWAP DDUP  
  9844. TYPE   ( addr count -- ) 
  9845. TYPE outputs a character string to the EMIT device.  The string starts at address ADDR and is COUNT characters long .  TYPE will type a maximum number of characters determined by the variable MAX-TYPE to prevent runaway output.   
  9846. (If you accidentally TYPE something that messes up the screen font, enter a control 'O' to fix it.)  
  9847. " Hello" COUNT TYPE  ( print Hello ) 
  9848. Related Words: ID. EMIT COUNT  $TYPE ."  
  9849. TYPEFILE    ( <filename> -- ) 
  9850. Output a file to the current output device.  It is similar to the AmigaDOS CLI 'TYPE' command in that it can be paused and restarted from the keyboard.  See ?PAUSE.   
  9851. TYPEFILE S:STARTUP-SEQUENCE  ( see file ) 
  9852. Related Words: ?PAUSE FOPEN DOLINES  
  9853. GL -      Glossary
  9854.  
  9855.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  9856.  
  9857.     Glossary    GL -  
  9858.  
  9859.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  9860.  
  9861.  
  9862.  
  9863.  
  9864.  
  9865. U*   ( u1 u2 -- du )   " u times" 
  9866. Same as UM*  
  9867. Included for compatibility with FIG and '79  
  9868. U.   ( n -- )   "u dot" 
  9869. Print N as an UNSIGNED number. The number printed will be positive even if the highest bit, the sign bit, is on.   
  9870. Definition:  : U.   ( n -- )  0 D. ;  
  9871. -3 U.  ( prints 4,294,967,293 ) 
  9872. Related Words: D.R .HX .R D. .HEX  
  9873. U/   ( du u -- u-rem u-quotient )
  9874. du = double cell unsigned dividend 
  9875.  u = unsigned divisor 
  9876. u-rem = unsigned remainder 
  9877. u-quotient = unsigned quotient  
  9878. Divide a double unsigned number by an single precision unsigned number leaving an unsigned remainder and quotient.   
  9879. Standards:  Called U/MOD in '79, called UM/ in  '83
  9880. Related Words: */MOD  M/  /  M/MOD CELL/ D2/ 2/ W/ /MOD DU2/  U2/  
  9881. U2*   ( u -- u*2 )   "u 2 star" 
  9882. U2* multiplies the value on the top of the stack by 2 (which is really a left shift). The MSB is shifted out and thrown away. The LSB gets a 0  
  9883. Standards: JForth unique  
  9884. Usage: For left shift of bits, or address manipulations and fast math.   
  9885. Related Words: U* DU2* 2* ASHIFT SHIFT  
  9886. U2/   ( u -- u/2 )   "u 2 slash" 
  9887. U2/ shifts the top value on the stack one place to the right. Least significant bit LSB is shifted out and  discarded. 0 is shifted in to the MSB position. This is  the same as dividing by 2 .   
  9888. Standards: JForth unique  
  9889. Usage: When shift right is needed for low level code writing or for dividing by 2.   
  9890. Related Words: CELL/ D2/ 2/  DU2/ ASHIFT SHIFT  
  9891. U<   ( u1 u2 -- flag )   " u less than" 
  9892. Unsigned less-than test.  True if U1 < U2, otherwise false.   
  9893. 5 -3 .S U<  ( strange but TRUE ) 
  9894. Related Words: U. U* U> > <  
  9895. U>   ( u1 u2 -- flag )   "u greater than" 
  9896.   Unsigned greater-than test. True if U1 > U2, otherwise false .   
  9897. Related Words: U<  
  9898. UM*   ( u1 u2 -- du )   "u m times" 
  9899. UM* inputs two single cell unsigned numbers and returns  an unsigned double cell product.  From file JU:MULTISTANDARD  
  9900. Standards:  '83, called U* in FIG and '79  
  9901. M* is to be used if a signed product is needed.   
  9902. Related Words: M* * */ */MOD U2* 2* DU2*  
  9903. UM/   ( du u -- u-rem u-quotient )   "u m slash"
  9904. Same as U/
  9905. UNMARKFCLOSE  ( file-pointer -- ) "un mark f close" 
  9906. UNMARKFCLOSE is used to remove the file-pointer from the list of files marked to be automatically closed by (QUIT).  File-pointers may be added to the list with MARKFCLOSE.   
  9907. Forth programs usually execute (QUIT) as the final operation in restarting an application, when an error requires restarting (usually indirectly, via QUIT or ?ABORT").   
  9908. When an application terminates normally, it should use UNMARKFCLOSE to remove the file-pointer from the QUIT list, just prior to closing the file if it was placed there by MARKFCLOSE.   
  9909. For additional information, see the appendix "JForth File Manager".   
  9910. Standard: JForth Unique  
  9911. : EXAMPLE ( <filename> -- )
  9912.     FOPEN ?DUP         \ get the filename, did it open? 
  9913.     IF   DUP MYFILE !  \ yes, save pointer in my variable 
  9914.         MARKFCLOSE     \ set it to auto-close at quit 
  9915.         RUN-MY-PROGRAM \ do whatever I want with the file 
  9916.         MYFILE @ DUP   \ need to do TWO thing to the pointer: 
  9917.         UNMARKFCLOSE   \ remove it from the QUIT list...  
  9918.         FCLOSE         \ and close the file 
  9919.     ELSE ." can't open the file " 
  9920.     THEN
  9921. ;
  9922. Related Words: MARKFCLOSE  QUIT  ABORT   ABORT"  
  9923. UNMARKFREEBLOCK ( mem-block -- ) "un mark free block" 
  9924. UNMARKFREEBLOCK is used to remove the memory-block from the list of memory-areas marked to be automatically freed by (QUIT).  Memory-blocks may be added to the list with MARKFREEBLOCK.  When an application terminates normally, it should use UNMARKFREEBLOCK to remove it from the QUIT list just prior to freeing the memory if it was placed there by MARKFREEBLOCK.   
  9925. For additional information, see the appendix "JForth Memory Manager".   
  9926. Standard: JForth Unique  
  9927. : EXAMPLE ( - )
  9928.     0 1024 ALLOCBLOCK ?DUP \ alloc 1K, did it allocate? 
  9929.     IF  DUP MYMEM !       \ yes, save pointer in my variable 
  9930.         MARKFREEBLOCK     \ set it to auto-free at quit 
  9931.         RUN-MY-PROGRAM    \ do whatever I want to do with the mem 
  9932.         MYMEM @ DUP       \ need to do TWO thing to the pointer...  
  9933.         UNMARKFREEBLOCK   \ remove it from the QUIT list...  
  9934.         FREEBLOCK         \ and free the memory 
  9935.     ELSE ." can't allocate memory " 
  9936.     THEN
  9937. ;
  9938. Related Words: MARKFREEBLOCK  QUIT  ABORT   ABORT"  
  9939. UNRAVEL  ( -- )
  9940. Analyses the return stack and prints a list of the words currently executing.  Often used when reporting errors to find out what word caused the error.
  9941. INCLUDE? UNRAVEL JU:UNRAVEL
  9942. : STOPIT  ( -- ) ." Error!" UNRAVEL QUIT ;
  9943. : FOO  23 45 + . STOPIT ;
  9944. : ZAPPER  ." Test" CR FOO ;
  9945. ZAPPER
  9946. If you do this you should see the names of ZAPPER, FOO and STOPIT in the list.  To install UNRAVEL as part of QUIT, use START.UNRAVEL.QUIT.  To remove it, use STOP.UNRAVEL.QUIT.
  9947. Related Words: R@ RDEPTH >NAME
  9948. UNSMUDGE   ( -- )   
  9949. Clear the smudge bit in the LATEST definition so FIND will locate it.  Same as REVEAL. 
  9950. Standards: JForth  
  9951. Related Words: SMUDGE REVEAL  
  9952. UNTIL   ( flag -- ) 
  9953. Will loop back to BEGIN if FLAG = FALSE.  Otherwise continue.   
  9954. Standards:  Run time action is '79, '83, FIG.   
  9955. Compile time action is JForth unique.  
  9956.  
  9957. : YAKYAK 
  9958.      BEGIN ." Hit key to stop!" CR 
  9959.          ?TERMINAL   ( leave flag ) 
  9960.      UNTIL KEY DROP  ( clean up character hit )
  9961. At compile time:   ( address-of-loop-body begin_flag -- )     
  9962. BEGIN_FLAG is for compiler security.  ADDRESS-OF-LOOP-BODY  is address to branch to if FALSE.  UNTIL puts a ?BRANCH into the dictionary.   
  9963. Related Words: BEGIN WHILE REPEAT UNTIL-NOT END  WHILE-NOT DO LOOP AGAIN  
  9964. UNTIL-NOT    until not 
  9965. Same as UNTIL only stays in the loop under the opposite condition as UNTIL .  Simple concatenation of NOT and UNTIL .   
  9966. Standards: NOT COVERED. JForth EXTENSION.   
  9967. : EXAMPLE  ( -- )
  9968.     5 BEGIN  ." loop-body" 1- DUP 0> 
  9969.       UNTIL-NOT DROP
  9970. Related Words: UNTIL  BEGIN  
  9971. UP!   ( addr -- )   "u p store" 
  9972. UP! is not called in JForth V2.0.   
  9973. Standards:  JForth unique  
  9974. Related Words: UP@  
  9975. UP@   ( -- addr )   "u p fetch" 
  9976. Fetch the user area pointer address.  All user-variables (storage area accessible by only the owning task) are indexed from this JForth-relative base pointer.   
  9977. Standards: JForth unique  
  9978. Related Words: USER USP US> >US UP!  
  9979. UPPER   ( address count -- ) 
  9980. Convert a string at address that is count characters long to upper-case.   
  9981. : GETPASSWORD  ( -- flag ) 
  9982.     BL WORD DUP COUNT UPPER  ( convert mixed case to upper) 
  9983.     " SECRET-PASSWORD"  $=
  9984. Related Words: MAKEUCASE TEXT=? $= OUTPUT-CASE NOCASE HICASE LOCASE TOUPPER  
  9985. UPPERC@   ( addr -- upper-case-character ) 
  9986. UPPERC@ is used to fetch a character from addr, converting it in the process to upper-case if it is alphabetic.  If the ASCII character is not between lower-case a to z, it is not changed.  The contents of addr are not affected.   
  9987. Related Words: C@  UPPER  MAKEUCASE  LWORD  
  9988. US-DEPTH   ( -- user-stack-depth-in-cells )   "u s depth" 
  9989. US-DEPTH returns the number of cells that have been pushed on the user stack, analogous to DEPTH.   
  9990. Related Words: US> US@ USP US-PICK DEPTH  
  9991. US-PICK   ( n -- nth-item-of-user-stack )   "u s pick" 
  9992. US-PICK picks the nth cell off user stack, much like PICK does for the data stack.   
  9993. Standards: JForth unique.   
  9994. Related Words: US> US@ USP US-PICK  
  9995. US>   ( n --US-- )   ( -- n )   "u s from" 
  9996. This is the user stack equivalent of R> . It pops one item off the user stack onto the data stack .   
  9997. Standards: JForth unique.   
  9998. Related Words: USP US> >US INIT-USP  
  9999. US@   ( -- n )  ( n --US-- n ) 
  10000. US@ copies the top of the user stack onto the stack .  This is the user stack equivalent of R@ .   
  10001. Definition: : US@ ( -- N )  USP @ @ ;  
  10002. Standards: JForth unique.   
  10003. Usage: Control of an extra stack .   
  10004. Related Words: USP US> >US INIT-USP  
  10005. USER 
  10006. Compile time:  ( name --IN- ) Eats name for header from input stream.   
  10007. Run time:      ( -- addr )   Leaves address of user-owned data area.   
  10008. USER is a defining word similar to VARIABLE.  It defines a data type that is only accessible to the task that created it.  This is done by providing each task with it's own USERAREA, from which storage space is allocated.   
  10009. Each user area contains a counter (called USER#) which is used to point to the next available cell to be allotted.  Each time USER is invoked:  
  10010. 1.  A name is created in the dictionary, from that which follows the USER declaration.
  10011. 2.  The current value of USER# is fetched, installed into the just-created definition, then incremented by 4 (1 cell) and placed back in USER#.   
  10012. Note that when the user-variable later executes, it will place the address of the user-specific data area on that users stack.   This address will be equal to the user offset stored in the definition, PLUS the address of that users user area (gotten by UP@).   
  10013. Standards: JForth UNIQUE.   FIG USER expects an offset  ( n -- <name> ).   
  10014. USER MY-VAR 
  10015. 23 MY-VAR ! 
  10016. Related Words: USER# UP@ #U  
  10017. USER#   ( -- user-addr ) 
  10018. This user-variable is used by the USER facility to track the allotment of the user area.  See USER.   
  10019. USERCLEANUP   ( -- )
  10020. See the chapter on CLONE.   
  10021. USP@  ( -- addr-of-top-of-user-stack )  "u s p fetch" 
  10022. Returns the address of the top of the user stack, as SP@ does for the data stack.   
  10023. Standards: JForth unique.   
  10024. Related Words: USP US> >US INIT-USP  
  10025. VALID-NAME?   ( possible-NFA -- seems-valid-flag ) 
  10026. VALID-NAME?  takes a possible NFA and returns a true if it appears to be a valid header.  It conducts a thorough test on the passed in address, testing if it physically meets the qualities of a real name field.   
  10027. Standard: JForth Unique. 
  10028. Related Words: ID.  >NAME    
  10029. VALUE   ( n <name> -- ) 
  10030. Creates a self fetching variable.  VALUEs act like a constant except you can change them using the word -> .   
  10031. INCLUDE? VALUE JU:VALUE 
  10032. 765 VALUE MY-VALUE 
  10033. MY-VALUE .    ( will print 765 ) 
  10034. 19 -> MY-VALUE    ( change value ) 
  10035. MY-VALUE .    ( will print 19 ) 
  10036. Related Words: -> VARIABLE CONSTANT CREATE { DOES>  
  10037. VARIABLE   ( <name> -- ) 
  10038. Define a named 32 bit storage location.  You can store values into this area for later use.  The initial value is zero.  When the word is executed it leaves its address on the stack.   
  10039. Standards: '79  '83. fig expected an initial value for the variable at compile time.   
  10040. VARIABLE MY-VAR 
  10041. MY-VAR .   ( print address of MY-VAR ) 
  10042. 73 MY-VAR  !  ( set value ) 
  10043. MY-VAR @ .    ( prints 73 ) 
  10044. Related Words: USER CONSTANT CREATE VALUE  
  10045. VLINK>VLATEST   ( voc-link-addr -- addr-of-name ) 
  10046. VLINK>VLATEST converts a VOC-LINK, vocabulary link pointer, address,  to the address of the NAME of the latest  definition in that vocabulary.  See section on Vocabularies for more information.   
  10047. Standards: JForth UNIQUE  
  10048. Related Words: VOC-LINK VLINK>VLATEST  VLATEST>VLINK     
  10049. VLINK>'   ( voc-link-addr -- cfa-of-vocabulary )  
  10050. VLINK>' converts a VOC-LINK, vocabulary link pointer, address  to the CFA address for that vocabulary.  See section on Vocabularies for more information.   
  10051. Standards: JForth UNIQUE  
  10052. VOC-LINK @ VLINK>' >NAME ID.  
  10053. Related Words: VOC-LINK VLINK>VLATEST  VLATEST>VLINK     
  10054. VLATEST>VLINK  ( nfa-of-vocabulary -- voc-link-addr )  
  10055. VLATEST>VLINK converts the address of the NAME of a vocabulary to  the VOC-LINK address, then vocabulary link pointer address, of that vocabulary.  See section on Vocabularies for more information.   
  10056. Standards: JForth UNIQUE  
  10057. Related Words: VOC-LINK VLINK>VLATEST  VLATEST>VLINK     
  10058. VLIST   ( -- ) 
  10059. See WORDS.  
  10060. Related Words: WORDS ALL-WORDS WORDS-LIKE ORDER   
  10061. VOC-LINK   ( -- addr ) 
  10062. VOC-LINK is a USER variable pointing to the linked list of vocabularies in reverse order of definition.  See section on Vocabularies for more information.   
  10063. Standards: Not covered .  But common in FIG '79 '83 systems.   
  10064. Related Words: VOCABULARY ORDER WORDS ALL-WORDS VLINK>VLATEST VLINK> VLATEST>VLINK   
  10065. VOCABULARY   ( <name> -- ) 
  10066. VOCABULARY is a defining word that creates new vocabularies.  Vocabularies are used to collect a group of word that relate to a specific area, eg. music, robotics.  You can turn on or off a vocabulary to make these words available or unavailable.  See section on Vocabularies for more information.   
  10067. Standard: '83.   
  10068. Related Words: VOCABULARY ORDER WORDS ALL-WORDS VLINK>VLATEST VLINK> VLATEST>VLINK   
  10069. W!   ( n even-addr -- )   "w store" 
  10070. Store lower 16 bits of N to an even address.   
  10071. Related Words: W@ W, W->S  
  10072. W,   ( n -- )   "w comma" 
  10073. Add the lower 16 bits of N to the dictionary at HERE. Same as   ,   only a 16 bit value.   
  10074. \ Create a table of 16 bit values 
  10075. CREATE TABLE16  23 W, 497 W, 71 W, 
  10076. TABLE16 1 2* + W@ .  ( print 497 ) 
  10077. Related Words: , ALLOT HERE DP  CFA,   
  10078. W->S   ( w -- n ) 
  10079. Sign extend a 16 bit value W to a 32 bit value N.  See B->S .   
  10080. VARIABLE MY-VAR 
  10081. HEX -27 MY-VAR W! 
  10082. MY-VAR W@ .   ( not -27 !!! ) 
  10083. MY-VAR W@ W->S . ( print -27 ) 
  10084. Related Words: S->D  B->S W@ W!   
  10085. W/   ( n w  -- n/w )   "w slash" 
  10086. n = dividend ( one cell or 32 bits in size) 
  10087. w = divisor (one half cell or 16 bits in size) 
  10088. n/w = 16 bit quotient in lower half of cell 
  10089. 32 bit by 16 bit divide.  Several times faster than   /  because it can use the 68000 hardware divide. Does not sign extend 16 bit result n/w . Dividing by zero will cause a trap.   The remainder is discarded.   
  10090. DECIMAL  50 4 W/ . ( displays 12 )  
  10091. Related Words: / U/ D/ 2/ ASHIFT /MOD  W->S   
  10092. W@   ( even-addr -- w )   "w fetch" 
  10093. Fetch a 16 bit value from the address given.  W@ will not sign extend the word.  Use W->S to sign extend.   
  10094. Standards: same as standard @ in most 16 bit Forths.   
  10095. CREATE SHORTVAR -34 W, 
  10096. SHORTVAR W@  W->S .  
  10097. Related Words: W! W, W->S  
  10098. WARNING"   ( flag <string"> -- ) 
  10099. Types the quote delimited string if flag is true.   
  10100. : TEST.OVERFLOW 
  10101.     DEPTH 100 > 
  10102.     WARNING"  Lots of stuff on stack!" ; 
  10103. Related Words: ABORT" QUIT ."  
  10104. WHAT'S   ( <name> -- cfa ) 
  10105. Return the CFA that a deferred word is set to execute.  This is useful when you want to set a deferred word temporarily then restore its original value.   
  10106. Standards: JForth UNIQUE  
  10107. WHAT'S EMIT  >NAME ID.   
  10108. Related Words: IS DEFER GLOBAL-DEFER  
  10109. WHEN-SCANNED   ( nfa -- ) 
  10110. WHEN-SCANNED is a DEFERed word that is executed by SCAN-VOC and SCAN-ALL-VOCS for each word that they examine.  It is used to write WORDS and ALL-WORDS and WORD-LIKE . See SCAN-ALL-VOCS .   
  10111. Standard: JForth UNIQUE.   
  10112. Related Words: WHEN-VOC-SCANNED SCAN-VOC SCAN-ALL-VOCS  
  10113. WHEN-VOC-SCANNED   ( voc-addr -- ) 
  10114. WHEN-VOC-SCANNED is a DEFERed word that is executed by SCAN-ALL-VOCS and SCAN-ALL-VOCS for each vocabulary that is scanned.  It is used to write WORDS and ALL-WORDS and WORD-LIKE . See SCAN-ALL-VOCS .   
  10115. Standard: JForth UNIQUE.   
  10116. Related Words: WHEN-SCANNED SCAN-VOC SCAN-ALL-VOCS WORDS ALL-WORDS  
  10117. WHILE   ( flag -- ) 
  10118. Used in the form:  
  10119. BEGIN xxxx WHILE yyyy REPEAT 
  10120. The code XXXX must leave a flag.  If the flag is TRUE then YYYY will be executed.  Otherwise, execution will jump to the code after REPEAT.   
  10121. : BIGMISTAKE  ( -- , loop while answering yes ) 
  10122.     BEGIN ." Launch a missile?" Y/N 
  10123.     WHILE ." Bombs away!" cr 
  10124.     REPEAT ; 
  10125. Related Words: BEGIN REPEAT WHILE-NOT UNTIL  
  10126. WHILE-NOT   ( flag -- ) 
  10127. Simple concatenation of NOT and WHILE .  Instead of  
  10128. BEGIN xxxx NOT WHILE yyyy REPEAT 
  10129. you can use  
  10130. BEGIN xxx WHILE-NOT yyy REPEAT 
  10131. which is faster.   
  10132. Related Words: BEGIN REPEAT WHILE UNTIL NOT   
  10133. WILLGET   ( -- , <modulename> <wordname> )
  10134. See the chapter on MODULES.   
  10135. WINDOWSTRING ( -- addr )
  10136. Returns the address of the string used to open the JForth window.  Change this string and SAVE-FORTH if you want to resize or change the title of the default JForth window.
  10137. WINDOWSTRING 60 DUMP
  10138. WITHIN?   ( N lower upper -- flag ) 
  10139. WITHIN? compares a number to an upper and lower bounds.  Returns a TRUE if N is both greater than or equal to lower and less than or equal to upper.   
  10140. 20  -5 100 WITHIN? . ( will be true )  
  10141. 20  20 30  WITHIN? . ( true )  
  10142. 20  21 30  WITHIN? . ( false ) 
  10143. Related Words: >= <=   
  10144. WMOVE   ( from-addr to-addr #words -- ) 
  10145. WMOVE  is similar to MOVE but it moves n words instead of bytes, and requires the to and from addresses to be even ( on the 68000 ).  This is faster than CMOVE.   
  10146. Standard: JForth unique.   
  10147. Related Words: MOVE CMOVE CMOVE> $MOVE  
  10148. WORD   ( delim-char <text> -- $addr ) 
  10149. Reads one word from the input stream using the character on the stack as the delimiter. An ASCII blank is usually used.  WORD moves the text string <TEXT> to the dictionary address $ADDR with the count in the first byte, and leaves $ADDR on top of the stack.  $ADDR typically equals HERE.  WORD will ignore leading occurrences of the delimiter character.   
  10150. WORD will update the TIB pointer >IN to point to the character following the text.   
  10151. If SKIP-WORD has been called then WORD will ignore the following text and simply return the address of HERE .  This can be used to pass a string to a word that normally gets its text from input.  See SKIP-WORD for more info.   
  10152. Here is an example of using WORD to define the comment operator.   
  10153. : (  ASCII ) WORD DROP ; 
  10154. Related Words: HERE EXPECT TEXT KEY UNWORD >IN FIND SKIP-WORD  
  10155. WORD-SWAP   ( abcd -- cdab ) 
  10156. Swap upper and lower 16 bit parts of a 32 bit number.  A B C and D in the diagram are bytes.   
  10157. HEX 12345678 WORD-SWAP .  ( print 56781234 ) 
  10158. Standards: JForth unique  
  10159. Related Words: W@ W! BYTE-SWAP  
  10160. WORDS   ( -- ) 
  10161. WORDS causes a printout to the current device of all JForth words in the CONTEXT vocabulary.   
  10162. Standards: '83. Called VLIST in FIG and '79 . Both are included in JForth.   
  10163. Related Words: ALL-WORDS VLIST ORDER VOCABULARY SCAN-VOCS  
  10164. WORDS-LIKE ( <partial-name> -- ) 
  10165. Searches dictionary for words whose name contains the partial name given. 
  10166. WORDS-LIKE EMIT
  10167. will print FEMIT FLUSHEMIT (EMIT) plus any other words containing "EMIT".  WL is a short alias for WORDS-LIKE. WORDS-LIKE is also attached to the function key <F6>. 
  10168. Related Words: FILE? WORDS 
  10169. X!   ( nx ... n2 n1 addr x -- ) 
  10170. Store x cells from stack to memory starting at address ADDR. Cells are transferred so that the most significant cell, nx, is at addr, with less significant cells in ascending memory. Works on ODD or EVEN addresses.   
  10171. Standards: JForth UNIQUE   
  10172. VARIABLE MY-DVAR CELL ALLOT 
  10173. 9. MY-DVAR 2 X!  (  stores the double number 9. in MY-DVAR )  
  10174. Related Words: X@ X>R XR> D!   
  10175. X>R   ( nx...n2 n1 x -- )   ( --R-- nx...n2 n1 )  
  10176. Transfers x cells from the data stack to the return stack .   
  10177. Standards: JForth UNIQUE.   
  10178. : EXAMPLE  2  46 88 99  3 X>R  . ( displays 2 ) 
  10179.     3 XR>  3   XDROP ( empty stack ) ;    
  10180. Related Words: XR> XR@ XDROP XDUP  
  10181. X@   ( addr x -- nx...n2 n1 )   "x fetch" 
  10182. Fetch x cells (nx...n2 n1 ) from memory starting at address ADDR to the data stack. ADDR is address of nx and addresses are incremented by one cell address space to fetch each new N.   See  X! .   
  10183. Standards: JForth UNIQUE  
  10184. CREATE FOO  11 ,  22 ,   33 , 
  10185. FOO 3 X@  .S   ( 33 22 11 on stack )
  10186. Related Words: XR> X>R XR! XDUP XDROP X!  
  10187. XDROP   ( nx...n2 n1 x -- ) 
  10188. Drop X cells from the data stack. This is very fast regardless of the number of items dropped.   
  10189. Standards: JForth UNIQUE  
  10190. 11 22 33 44   4 XDROP  ( empty stack ) 
  10191. Related Words: XR> X.R XR@ XDUP  
  10192. XDUP   ( nx ...n2 n1 x --  nx...n2 n1  nx...n2 n1 )  
  10193. Duplicate the top x cells on the stack in order and push the whole set on top of the stack .   
  10194. Standards: JForth UNIQUE  
  10195. 11 22 33  3 XDUP .S ( print: 11 22 33 11 22 33 ) 
  10196. Related Words: XR> X>R XR@ XDROP  
  10197. XOR   ( n1 n2 -- n3 ) 
  10198. Perform bit by bit EXCLUSIVE OR of N1 and N2.  Here is the truth table for an EXCLUSIVE OR operation on two bits:  
  10199. A   B  ->  A.XOR.B 
  10200. 0   0         0 
  10201. 1   0         1 
  10202. 0   1         1 
  10203. 1   1         0 
  10204. (Performing an XOR with -1 has the effect of reversing the value of the bits in a number.)  
  10205. Standards: '79 '83  fig  
  10206. BINARY 0011 1010 XOR .  ( print 1001 ) 
  10207. 010101 111111 XOR . ( print 101010 ) 
  10208. Related Words: OR AND NOT  
  10209. XPICK   ( ..... N X -- Xcells-from-Ncell-deep ) 
  10210. XPICK takes the cells N deep and the number of cells X to pick and picks them from the stack. Zero is the 1st cell.   
  10211. Standards: JForth UNIQUE  
  10212. 99 88 77 66  (  -- 99 88 77 66 ) 
  10213. 1 2 XPICK .S (  -- 99 88 77 66 88 77 ) 
  10214. Related Words: R> >R X>R  XR@ XDROP XDUP PICK RPICK  
  10215. XR>   ( x --  nx ...n2 n1 n0 ) 
  10216. ( nx ...n2 n1 n0 --R-- )   "x r move" 
  10217. Move x cells ( n1 n2 up through nx ) from the return stack to the data stack in order.   
  10218. Standards: JForth UNIQUE  
  10219. Related Words: R> >R X>R  XR@ XDROP XDUP   
  10220. XRDROP   ( x -- )   "x r drop" 
  10221. XRDROP drops X items off the return stack.   
  10222. Standards: JForth UNIQUE  
  10223. : EXAMPLE   4 >R  38 >R  30 >R   3 XRDROP ; 
  10224. Related Words: R> >R X>R  XR@ XDROP XDUP   
  10225. Y/N   ( -- flag , or quit )   "y slash n" 
  10226. Y/N is a word that displays the message "...Yes, No or Quit (y/n/q)?" then waits for 1 of 3 keys: y n or q  in either upper or lower case.  If q it will call QUIT, if y it will return a true flag, and if n it will return a false flag (zero).   
  10227. Standards: JForth UNIQUE  
  10228. [   ( -- )   "open bracket" 
  10229. Suspends the operation of the compiler, causing following input to be INTERPRETed, rather than compiled.  Usually paired with the ] character, which re-invokes the compiler.   
  10230. Standard: fig '79 '83  
  10231. Here is an example where the calculation of a constant is done at compile time to reduce the run time burden.   
  10232. : EXAMPLE   [ HEX 7A43 17 / DECIMAL ] LITERAL + 
  10233.    [ ." Prints right now!!" ] ; 
  10234. Related Words: ] STATE IMMEDIATE INTERPRETING? COMPILING? LITERAL  
  10235. [COMPILE]   ( <name> -- )   "bracket compile" 
  10236. Forces the compilation of the next word in the input stream even if it is an IMMEDIATE word.   
  10237. : VERBOSE.LITERAL   ( N -- , compile N ) 
  10238.     DUP ." N = " . CR 
  10239.     [COMPILE] LITERAL  ( execute LITERAL later ) 
  10240. ; IMMEDIATE
  10241. : FOO [ 234 9 / ] VERBOSE.LITERAL . ; 
  10242. FOO .
  10243. Related Words: []  CFA   
  10244. []   ( object -- ) 
  10245. Used to indicate late binding in ODE. See chapter on ODE.   
  10246. : PRINT.OBJECT ( object -- ) 
  10247.     PRINT: [] ; 
  10248. Note:  This is also sometimes used as a shorthand for [COMPILE] whose use is preferred.   
  10249. Related Words: [COMPILE]  
  10250. \   ( <rest-of-line> -- )   "back slash" 
  10251. Ignores the rest of the line during compiling or interpreting.  Treat it as a comment.   
  10252. \ This is a comment.  
  10253. ." DO THIS!"  \ But not this! 
  10254. Related Words: ( )  
  10255. ]   ( -- )   "close bracket" 
  10256. Enter compile mode by setting STATE to TRUE.  Used with [ to temporarily suspend and resume compilation.   
  10257. This is sometimes entered accidentally because of it's proximity to the carriage return key.  Just enter [ to get back your OK prompt.   
  10258. Standard: fig '79 '83  
  10259. : example   [ 2 4 + . ]  [ 9 ] literal . ; 
  10260. \ Will display 6 when compiled and 9 when run.  
  10261. Related Words: [ STATE IMMEDIATE INTERPRETING? COMPILING?   
  10262. GL -      Glossary
  10263.  
  10264.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  10265.  
  10266.     Glossary    GL -  
  10267.  
  10268.     ! " # $ % & ` ( ) * + ' - . / 0-9 : ; < = > ? @ AZ [ \ ] ^ _ az { | } ~
  10269.  
  10270.  
  10271.  
  10272.  
  10273.  
  10274. Appendices
  10275.  
  10276.  
  10277. Appendix A
  10278. Delta Research Biographies     
  10279. Mike Haas  
  10280. Mike first fell in love with Forth when he ported FIG Forth to a homebrew 6800 system.  He worked with Brian and Jim on the design of a Forth chip and is also a 'C' programmer.  Mike is also working on networking software for the Macintosh.  His work on JForth includes the assembly language kernal (the foundation of JForth), the Amiga system interface, CLONE, Modules, the CALL facility that makes the Amiga libraries accessible, and more.  Mike also developed Textra, the text editor for programmers, and LCDCalc, an attractive calculator that looks like a desktop LCD model.
  10281. Phil Burk  
  10282. Phil became a Forth fan developing code for a music system running on a, then state of the art, S-100 68000 system.  He has developed a Forth for the VAX and for a homebrew 68000 computer.  He worked first as a physicist, then later developed interactive graphics/mapping systems on mainframes using 'C' and FORTRAN.  His hardware projects have included small custom computers, guitar to MIDI convertors, and synthesizer modules.  His work on JForth includes structures, ODE ,  the graphics toolboxes, the '.j' files, Hashing, History, Source Level Debugger, IFF, the new local variables, and many demos.  Phil also works on HMSL, the Hierarchical Music Specification Language.  HMSL is an experimental composition language based on JForth.  One of Phil's latest interests is in developing real time sound synthesis software using the 56000 Digital Signal Processor.
  10283. Brian Donovan  
  10284. Brian first became interested in Forth when he saw a complete 8080 macro assembler contained within a 1/4 page footnote in an IEEE magazine.  He has been programming for about 10 years doing mostly Forth, assembly and 'C'. His hardware projects have included electromechanical games, electric vehicles, telephone network testers, smart refrigerators and the design of a custom Forth processor.  Brian has also worked with Novix on their Forth processor.  His work on JForth includes part of the kernal, the original local variables, vocabularies, WORDS-LIKE, multistandard, and more. 
  10285. Jim King  
  10286. Jim is a chemist, a musician, an attorney, and an electrical engineer.  He is also a 'C' and Forth programmer.  He has worked with Mike and Brian on the Forth chip, and other hardware projects including audio digital signal processors.  He helped put together the manual, and did quality assurance.   
  10287.  
  10288.  
  10289. Appendix B
  10290. Resources
  10291. On-Line
  10292. These resources are accessable via modem.  Due to the volatile nature of cyberspace, these resources may not be available in the future.
  10293. GENIE
  10294. GEnie is a national bulletin board run by General Electric.  They maintain a very active Forth Roundtable.  Enter M710 or FORTH.  Information available by calling (800)638-9636.  GEnie charges an hourly rate.
  10295. BIX
  10296. Martin Kees hosts a JForth vendor conference on BIX.  For information, call (800)227-2983.
  10297. Commotech Computers BBS
  10298. Commotech Computer store in San Diego has a JForth section on their BBS.  To get to the JForth stuff, go to the Mail Menu, then select "Other Section".  They also have some JForth related files.  If you use JRComm, set it for 16 color ANSI/IBM mode.  The phone number is:  (619)477-2368.
  10299. HMSL BBS
  10300. This is a free BBS intended for HMSL users, but it has a thread for the Amiga that has lots of JForth discussion.  Hosted by Robert Marsanyi.  Lots of high level electronic and computer music stuff.  Call (415)928-8246 but don't hog it.
  10301. InterNet
  10302. You can reach the authors, Phil Burk and Mike Haas, via the internet.  Send electronic mail to:
  10303. phil@mills.edu
  10304.     (or)
  10305. haas@starnine.com
  10306. Organizations
  10307. There are two major sources for information on FORTH.  They are:  
  10308. FORTH Interest Group 
  10309. P.O. Box 8231 
  10310. San Jose, CA 95155
  10311. (408) 277-0668
  10312. Fax: (408) 286-8988
  10313. FIG is a worldwide FORTH users group.  They publish FORTH Dimensions, an excellent journal of new ideas in FORTH.  Membership is highly recommended.  Get a copy of their order form which has almost every Forth related book and periodical including the Dr. Dobbs FORTH issues, and the publications of the Institute below.   
  10314. The Institute for Applied FORTH Research, Inc.  
  10315. 70 Elmwood Avenue 
  10316. Rochester, New York, 14611 
  10317. The Institute publishes the Journal of FORTH Applications and Research. This is a technically oriented publication.  They also organize an annual conference in Rochester.   
  10318. Publications
  10319. 1983. FORTH-83 Standard. A Publication of the FORTH  Standards Team. Mountain View Press. Mountain View, CA.   
  10320. Brodie, Leo. 1981. Starting FORTH. Prentice Hall, Inc.  Englewood Cliffs, New Jersey 07632.  A good introduction to FORTH.  It's emphasis is on polyFORTH, an older 16 bit FORTH, so not everything applies to JForth. Easy reading for beginners.
  10321. Burk, Polansky, Rosenboom. 1986. HMSL - Hierarchical Music Specification Language - Reference and User Manual, Frog Peak Music, Box 151051, San Rafael, CA, 94915-1051.  HMSL is an experimental music composition language written in JForth and ODE.
  10322. Haydon, Glen B. 1983. All about FORTH, An Annotated Glossary.  Mountain View Press. Mountain View, CA.  This provides source, and a description of the words in MVP FORTH.   
  10323. Kelly, Mahlon G. and Spies, Nicholas. 1986. Forth: A Text and Reference. Prentice-Hall Software Series, Englewood Cliffs, New Jersey 07632.  A comprehensive tutorial and reference manual that addresses some of the differences between FORTHs.  The emphasis is on MMSFORTH for the IBM PC.   
  10324. Chirlian, P. 1983. Beginning FORTH. Matrix. Beaverton, Oregon.  A good introduction for beginners.   
  10325. Derick, M. and Baker, Linda. 1982. FORTH Encyclopedia. Mountain View Press. Mountain View, CA. Provides source code and a detailed breakdown of the words in an 8080 version of FIG-FORTH.  Handy for people who want to dig into the internals of a FORTH.   
  10326. Hofert, D. 1985. A Bibliography of FORTH References, 2nd ed.  The Institute for Applied FORTH Research, Inc. Rochester, New York. A list of most articles published on FORTH, cross referenced.
  10327. Kane, Hawkins and Leventhal.  1981.  68000 Assembly Language Programming.  OSBORNE/McGraw Hill, Berkeley, CA.  Excellent book for learning 68000 assembly with many examples. An extensive reference section that covers every instruction in depth also makes this an excellent reference.  Recommended.
  10328. Loeliger, R. 1981. Threaded Interpretive Languages. Byte Books, Peterborough, N.H. A hackers book that describes the implementation of a TIL on a Z80.  The author implies that is not FORTH but it sure looks like it to me.  Good description of traditional inner interpreters.  JForth doesn't have an inner interpreter so this is not directly relevant.   
  10329. Winfield, A. 1983 The Complete FORTH. Sigma/Wiley, New York.  Excellent text on FORTH-79. Little advanced material.
  10330. Object-Oriented Programming
  10331. BYTE Magazine, Volume 11, Number 8, 1986, "Object Oriented Languages" issue; contains articles on object oriented Forth, NEON, ACTOR, Objective-C, Smalltalk, etc.
  10332. Cox, Brad J., Object Oriented Programming:  An Evolutionary Approach, Addison Wesley Publishing Company, 1986
  10333. Goldberg, Adele, and Robinson, David, Smalltalk-80: The Language and Its Implementation, Addison Wesley Publishing Company, 1983
  10334.  
  10335.  
  10336. ASCII Control Characters
  10337. Decimal-Hex-Character--Key--Typical-Usage----------------------
  10338.   0     00      NUL     ^@  Denotes end of string or no data.
  10339.   1     01      SOH     ^A
  10340.   2     02      STX     ^B
  10341.   3     03      ETX     ^C
  10342.   4     04      EOT     ^D
  10343.   5     05      ENQ     ^E
  10344.   6     06      ACK     ^F  ACKNOWLEDGEs reciept of message.
  10345.   7     07      BEL     ^G  Rings BELL on printer or terminal.
  10346.   8     08      BS      ^H  BACKSPACEs cursor.
  10347.   9     09      HT      ^I  Horizontal TAB.
  10348.  10     0A      LF      ^J  LINE FEED, AMIGA line terminator.
  10349.  11     0B      VT      ^K  Vertical TAB.
  10350.  12     0C      FF      ^L  FORM FEED, advance to next page.
  10351.  13     0D      CR      ^M  CARRIAGE RETURN, terminate line input.
  10352.  14     0E      SO      ^N
  10353.  15     0F      SI      ^O
  10354.  16     10      DLE     ^P
  10355.  17     11      DC1     ^Q  Resume host transmission, XON.
  10356.  18     12      DC2     ^R
  10357.  19     13      DC3     ^S  Stop host transmission, XOFF.
  10358.  20     14      DC4     ^T
  10359.  21     15      NAK     ^U  NOT AcKnowledged, NOT recieved.
  10360.  22     16      SYN     ^V
  10361.  23     17      ETB     ^W
  10362.  24     18      CAN     ^X
  10363.  25     19      EM      ^Y
  10364.  26     1A      SUB     ^Z
  10365.  27     1B      ESC     ^[  ESCAPE, general purpose, change mode.
  10366.  28     1C      FS      ^\
  10367.  29     1D      GS      ^]
  10368.  30     1E      RS      ^^
  10369.  31     1F      US      ^_
  10370.  
  10371. Printable Characters -- (Decimal Hex Character) ---------------
  10372.  32 20 SPAC 48 30 0    64 40 @    80 50 P    96 60 `   112 70 p   
  10373.  33 21 !    49 31 1    65 41 A    81 51 Q    97 61 a   113 71 q   
  10374.  34 22 "    50 32 2    66 42 B    82 52 R    98 62 b   114 72 r   
  10375.  35 23 #    51 33 3    67 43 C    83 53 S    99 63 c   115 73 s   
  10376.  36 24 $    52 34 4    68 44 D    84 54 T   100 64 d   116 74 t   
  10377.  37 25 %    53 35 5    69 45 E    85 55 U   101 65 e   117 75 u   
  10378.  38 26 &    54 36 6    70 46 F    86 56 V   102 66 f   118 76 v   
  10379.  39 27 '    55 37 7    71 47 G    87 57 W   103 67 g   119 77 w   
  10380.  40 28 (    56 38 8    72 48 H    88 58 X   104 68 h   120 78 x   
  10381.  41 29 )    57 39 9    73 49 I    89 59 Y   105 69 i   121 79 y   
  10382.  42 2A *    58 3A :    74 4A J    90 5A Z   106 6A j   122 7A z   
  10383.  43 2B +    59 3B ;    75 4B K    91 5B [   107 6B k   123 7B {   
  10384.  44 2C ,    60 3C <    76 4C L    92 5C \   108 6C l   124 7C |   
  10385.  45 2D -    61 3D =    77 4D M    93 5D ]   109 6D m   125 7D }   
  10386.  46 2E .    62 3E >    78 4E N    94 5E ^   110 6E n   126 7E ~   
  10387.  47 2F /    63 3F ?    79 4F O    95 5F _   111 6F o   127 7F DEL
  10388. AP -      Appendices
  10389.  
  10390.     Appendices    AP -  
  10391.  
  10392. AP -      Appendices
  10393.  
  10394.  
  10395.  
  10396.  
  10397.  
  10398.  
  10399.  
  10400. Appendix D
  10401. Sample Applications
  10402. We have provided several complete applications written in JForth.  They can be used either directly from JForth or they can be cloned and used as CLI commands.  Some of them demonstrate how to parse the command line, how to handle input errors and print "usage" information.  The file names all end with ".f" to distinguish the Forth source file from the cloned image file.   These files can be found on the "JA:" logical volume.
  10403. Please see the chapter on Clone for instructions on how to clone these applications.   
  10404. CR2LF.f - Carriage Return to Line Feed
  10405. Converts every Carriage Return in a file to a Line Feed.  This is handy if you get a file from some unfortunate Macintosh user.
  10406. DIAL.f - Quick Dialer using a Modem
  10407. DIAL is a CLI based utility that will look up and dial telephone numbers through your modem.  All you have to do is enter in a CLI: 
  10408. DIAL FRED
  10409. then pick up the phone and wait for Fred to answer.  DIAL will search a text file containing names and phone numbers.  When it finds a match it opens the SER: device and send a Hayes compatible message to your modem to dial. DIAL was written as a shell command because a mouse driven interface would take longer to use then just dialing the phone directly. 
  10410. To install DIAL you must: 
  10411. 1) Copy DIAL to your C: directory or other command directory.
  10412. 2) Set your serial preferences to match your modem. Eg. 1200 baud, 8 data bits, etc.
  10413. 3) Create a file called S:PHONELIST containing names and phone numbers.  Names and phone numbers cannot have spaces inside them.  For example:
  10414. JOE  1(707)555-1212                <-- GOOD
  10415. FRED FLINTSTONE 1 (707) 555-1234   <-- BAD
  10416. There are two ways to do this. One is using a text editor. The other is to use the ADD option of DIAL. For example:
  10417. DIAL ADD  WILMA  1(415)555-9876
  10418. The above will add WILMA's name to your phone list.  If the phonelist file does not exist, DIAL will create it.  To delete names, or to change names, just edit the file using a normal text editor like EMACS or Textra.  You can optionally specify a filename other than S:PHONELIST. For example: 
  10419. DIAL IRMA MYSTUFF:MYLIST
  10420. Since that would be more typing than just dialing it yourself, I recommend making an alias as follows: 
  10421. ALIAS  DL DIAL [] MYSTUFF:MYLIST
  10422. Put that alias in your S:SHELL-STARTUP file. 
  10423. Note that DIAL.f is shareware.  If you bought JForth then ignore that.  Consider yourself paid up.  Please feel free to give a cloned version of DIAL to a friend.  Just make sure you also give the Dial.README file which contains this documentation and information on the shareware aspects of Dial.
  10424. Docu.f - Automatic "Documentation" Generator
  10425. This application can be used to automatically generate simple documentation from a file.  It scans a file and prints any line that has a character in the first column, is not a comment, and has a stack diagram on it.  Thus the following lines would be printed if they occurred in a file.   
  10426. : ADD1  ( N -- N+1 , add one to a number )       
  10427. and 
  10428. VARIABLE NUM-FOO ( -- addr , number of foos) 
  10429. and 
  10430. : ADDEM  { aa bb -- aa+bb , add em up } 
  10431. The word which should be cloned is:  
  10432. : DOCU.FILE ( <filename> -- , document file ) 
  10433. DumpBrush.f - Dump a brush as JForth source code.
  10434. This application reads an IFF file containing a brush and outputs JForth compatible source code.  Thus you can use DPaint to create images and use them in your programs as gadget images.  Clone this program then enter:
  10435. DumpBrush >outfile brushfile
  10436. DumpIFF.f - Dump IFF file for analysis.
  10437. This scans an IFF file and prints out the contents of the chunks it encounters.
  10438. H2J.f - Convert a 'C' style ".h" file to a ".j" file.
  10439. This is the program we used to convert the Amiga DOS include files from 'C' code to JForth compatible code.  See the chapter on Amiga Libraries and Structures for more information.
  10440. Print.f - Print a File   
  10441. PRINT will output a file to a printer.  It prints the file name, page number, and date on each page.  It will also put line numbers on each line and skip over page perforations.  PRINT uses the left and right margins set in preferences to tell whether a line will wrap around.  Thus, lines that wrap will not mess up the page breaks.  You can turn off the line numbers using the "-n" option.  You can set the number of spaces for a tab using the "-t#" option.  The default tab spacing is 8 spaces between tabs.  To print a file called MYSOURCE without line numbers and with tabs set to 6 spaces, enter:  
  10442. PRINT MYSOURCE -N -T6 
  10443. If you want to send the output to a file instead of the printer, give that filename after the source file.  For example:  
  10444. PRINT MYSOURCE OUTFILE 
  10445. Rude.f - Print Rude Message using an Alert 
  10446. You can use this application to scare your friends or to control command files.  RUDE will read a quoted string from the command line and display it in an Alert just like a GURU Meditation Error.  The sight of these messages is enough to send a chill down the spine of most Amiga users.   
  10447. Rude asks you to hit the left button for Yes and the right for No.  A Yes will return 5 which can then be used to control the command file.  Here is a sample Amiga DOS command sequence (not Forth).   
  10448. RUDE "Should I install TextMangler 3.4?" 
  10449. IF WARN 
  10450.         RUN TextMangler 
  10451. ENDIF 
  10452. SortMerge.f - Merge Presorted Files   
  10453. SORTMERGE will take two presorted files and merge the output into a third file in sorted order.  This application is useful for adding new data to a large presorted file.  It can be handy when used with DOCU.FILE to create quicky documentation of a large multifile project.  Use the Amiga DOS SORT command to presort the input files.   
  10454. SORTMERGE infile1 infile2 outfile 
  10455. SayNumber.f - Recite a single-precision number in decimal
  10456. This JForth program parses the next word in the input stream and pronounces it in decimal-quantified form.  For example, the "Say" command, as furnished by Commodore, would pronounce 123 as "one, two, three", whereas this program will say "one hundred and twenty-three".   
  10457. saynum 123 
  10458. saynum 1989 
  10459. Terminal.f - Very Dumb Terminal Program  
  10460. This very simple terminal program can be used as a starting point for a fancier terminal program.   
  10461. Update.f - Copy newer files from one directory to another 
  10462. This JForth program examines two directories, then copies everything from <srcdir> to <destdir> that meet the specified criteria.   This is useful for maintaining backups of projects on floppies. UPDATE was written by Mike Haas for us at Delta Research as we worked on JForth on multiple Amigas.  We could merge our work by updating to a central computer.
  10463. Usage:  
  10464. Update  SourceDir DestDir [-date|-size -list -noask -both]  
  10465. -date = SourceDir/file is later than DestDir/file (default) 
  10466. -size = SourceDir/file is different size than DestDir/file 
  10467. -list = Don't really copy, just list the files that WOULD.  
  10468. -noask= Don't ask the user to verify input 
  10469. -both = Update only those files that exist in BOTH directories 
  10470. -all  = Check all files in the directory and any subdirectories.
  10471. Only the first letter of the option is required.  Here is an example that updates everything from a hard disk resident volume called MYWORK: to a floppy in DF1:.
  10472. UPDATE MYWORK: DF1: -N -A
  10473. WordCount.f - Count Words Lines and Chars 
  10474. This is very similar to the UNIX wc command except it gives you all the information at once.  The main word is called WC and is used like this:  
  10475. WC filename 
  10476.  
  10477.  
  10478. Appendix E
  10479. Style Guidelines
  10480. Naming Conventions
  10481. Forth allows ultimate flexibility in the naming of words.  For this reason, it is very important that the programmer be consistent in their naming.  Naming conventions can provide a road map to your code.  If you ever have to go back and revisit code months, or years, after writing it, you will be thankful if you used systematic naming.
  10482. This section will provide some of the naming conventions used in JForth and offer suggestions for your own naming. Since JForth naming is the combination of naming conventions from 3 developers, plus the standard Forth names, you may notice deviation from these suggested standards in JForth.  These suggestions will be more rigidly adhered to in the code I wrote since I often take my own advice.  Here goes:
  10483. Use Prefixes to Mark Related Code
  10484. By  a 2 or 3 letter prefix to all the words of a given system, you can clearly identify those words when they appear in other code.  This also helps eliminate naming conflicts if the prefixes are unique. Examples in JForth are:
  10485. GRxxx - for GRaphics words.
  10486. WD_xxx - for members of the WinDow structure
  10487. DBxxx - for internal Debugger Words
  10488. $xxx - for string related words.
  10489. Use Signature Characters to indicate a word's function.
  10490. You can often place characters in the name that indicate what a given word does. Examples are:
  10491. 4+  - adds 4
  10492. CONSOLE!  - set pointer in CONSOLE variables.
  10493. GR.COLOR!  - set graphics color (store in RastPort)
  10494. (xxx)  - parentheses usually indicate an internal function that is called from a deferred word, or that is compiled for run time action. Sometimes <> and [] are used.  Examples are:
  10495. (EMIT)  - simplest EMIT word.
  10496. (($"))  - run time action of ".
  10497. { and } are handy for marking words that are balanced. An example is:
  10498. DEBUG{  : FOO DUP + ; }DEBUG
  10499.  
  10500. Use Separators that indicate the Type of Word.
  10501. Compound words can use a separator that give you some idea of what the word is.  The separators I use are:
  10502. -  "hyphen" for variables, objects, and other data structures that leave an address on the stack.  These will generally be followed by a @ or !.  Examples are:
  10503. HIGHLIGHT-INPUT    GR-CURWINDOW    MAX-INLINE DL-LINENUM
  10504. _ "underscore" for constants, values, or other words that leave their actual value on the stack. Examples are:
  10505. OFFSET_BEGINNING    KH_HISTORY_SIZE    MEMF_CLEAR
  10506. . "dot" for action words, verbs. Examples are:
  10507. GR.DRAW    DEBUG.START    PIC.LOAD
  10508. Use full names for obscure words, short names for common words.
  10509. Short names are good for common words because no one likes to type long names all the time.  For rarely used words, however, you should use long names because you are less likely to remember what they do.  There is also less likelihood of naming conflicts with long names.  Remember when an application is cloned the names are removed and do not add size to the final image.
  10510. Writing Style
  10511. Here are some random thoughts on programming style.
  10512. Beware of compile time initialization.
  10513. If your program needs to open files, allocate memory, build jump tables or do anything with addresses, please put that code in a colon definition.  And please do not call that word in the file itself.  Doing so might seem like a handy little trick but it will bite you if you do a SAVE-FORTH or try to CLONE your program.  Opening files, and allocating memory generate addresses that are only valid for that time.  If you do a SAVE-FORTH or CLONE you may save an address that will not be valid the next time you use it.  
  10514. Here is an example of some BAD code in a file:
  10515. VARIABLE MYFILE
  10516. VARIABLE MYMEM
  10517. FOPEN RAM:DATA MYFILE !  \ Bad! Bad programmer!
  10518. MEMF_CLEAR 2000 ALLOCBLOCK MYMEM !  \ Very Bad!
  10519. Here is an example of doing it right.  Notice that we also check for error flags on initialization, and provide for automatic if we forget the code.  Using these techniques will save you from many puzzling errors.
  10520. VARIABLE MYFILE
  10521. VARIABLE MYMEM
  10522. : DOITRIGHT  ( -- error? , "Good programmer! Here bisquit.")
  10523.     TRUE \ default error return
  10524.     " RAM:DATA" $FOPEN ?DUP  \ did it work
  10525.     IF
  10526.         MYFILE !
  10527.         MEMF_CLEAR 2000 ALLOCBLOCK ?DUP
  10528.         IF
  10529.             MYMEM !
  10530.             DROP FALSE  \ change error?
  10531.         THEN
  10532.     THEN
  10533. ;
  10534. : CLEANUP ( -- )
  10535.     MYFILE FCLOSEVAR
  10536.     MYMEM FREEVAR
  10537. ;
  10538. IF.FORGOTTEN CLEANUP
  10539. Write short words.
  10540. Chuck Moore first pointed out that short definitions give you the most flexibility.  Nothing is worse than a word that does TOO much.  If you want part , but not all, of what a word does you cannot use it.  It is useless.  But if a word does only part of what you need you can add the rest.
  10541. Place Stack Diagrams on Every Word.
  10542. and sometimes inside words.  It is nearly impossible to read someone else's code if there are no stack diagrams.  I have also seen people trying to write a word when they don't know what its stack diagram should be, another impossible task.
  10543. Indent Paired Words to the Same Level.
  10544. This really helps improve the readability of code and can prevent many common mistake.  I have come to believe that IF, ELSE ,THEN, BEGIN, WHILE, REPEAT, UNTIL, CASE and ENDCASE should always be on their own line and cause a change in indentation level.  Here is an example of the suggested indentation style.
  10545. : FOO ( a -- b , do something )
  10546.     DUP 21 <  ( -- a flag, generate flag on previous line
  10547.     IF
  10548.         0  ( -- a 0 )
  10549.         DO  I . CR
  10550.         LOOP ." All done!" CR
  10551.     ELSE  ( a -- , good place for stack diagram )
  10552.         100 >
  10553.         IF  ." A really big!" CR
  10554.         THEN
  10555.     THEN
  10556. ;
  10557. Use >R R@ R> or Local Variables -
  10558. to avoid excessive stack dancing.  Too much  DUP  SWAP  DROP  will  ROT  your brain.
  10559. Write your Code Backwards using "Top Down" programming.
  10560. Start by writing  the top word in your application using an English like set of words.  Once this makes sense, write the next lower level, and so on.  Forth is enough like English that your "pseudo-code" can end up being legal Forth by the time you are done.  Forth is typically thought of as a "bottom up" language because it is so easy to hack in.  This is fine for pure experimentation but big projects demand the discipline of "top down" coding.
  10561. Initialization, Action, and Termination
  10562. Divide each module of your program into three parts: Initialization, Action, and Termination.  This will greatly simplify debugging because you will be able to completely initialize the system and then examine it before taking any action.  It also helps to organize your code.  Initialization typically consists of things like opening files, allocating memory, opening windows, or creating gadgets.
  10563. Transportability Techniques      
  10564. by Brian Donovan  
  10565. This appendix describes some techniques to use for writing transportable high level Forth code.   
  10566. The CELL concept.     
  10567. In Forth programs, you often want to skip over a single precision unit of data, or several single precision units of data, called "cell"s in Forth. Until  recently, most Forth programmers were explicitly using the numeric count needed on the machine they happened to be using.  This meant that on a 16 bit 8086 Forth they would use a 2+, on a 68000 32 bit Forth, like JForth, they would use 4+ , and on a NOVIX Forth CPU with word addressing, they would use 1+ .  For subtraction, multiplication and division by the single precision unit addressing size, the same situation would arise, thus, all programs written that way would be totally untransportable. A very simple and low overhead solution to this problem is to use CELL+ CELLS CELL/ CELL- and CELL instead of 1+ 2+ 4* etc.. whenever the program is working with cells.  We have painlessly used the same source for 16 bit and 32 bit computers of many types, and have found that programs written with CELL are much less obscure to read.   
  10568. In JForth:  CELL = 4  
  10569. One way to automatically assign CELL size in your programs is as follows:  
  10570. SP@ SP@ - ABS CONSTANT CELL 
  10571. : CELL+  CELL + ; 
  10572. : CELL-  CELL - ; 
  10573. : CELLS  CELL * ;   
  10574. : CELL/  CELL / ; 
  10575. With conditional compilation, you can pick out the optimal speed words for functions like CELLS and CELL/ .  In JForth, all these words are machine coded.   
  10576. INLINE concept.      
  10577. In more advanced Forth programs, programmers often want to create new inline data words (like ." ).  With the advent of segment threaded Forth, relative address Forths ( like JForth ) , and other new ways of implementing Forth, The top return stack item does not necessarily point data following the called word ( inline data ).  We use a slow version of LIT to illustrate some of the problems.   
  10578. This is slow LIT the way it would be in absolute addressing, address threaded Forth ( the good old standard unfancy Forth on a Z80 for example.)   
  10579. : SLOW-LIT  ( --- N )  ( CELL --INLINE-- ) 
  10580.     R@ @ R> CELL+ >R ; 
  10581. SLOW-LIT on a relative addressing Forth ( like JForth) :  
  10582. : SLOW-LIT   R@ >ABS @ R> CELL+ >R ; 
  10583. SLOW-LIT on some segment threaded 32 BIT, 8086 Forths:  
  10584. : SLOW-LIT-SEG   R@  SEG+OFF>ADDR  @  
  10585.     R> SEG+OFF>ADDR CELL+ ADDR>SEG+OFF >R ; 
  10586. ...pretty bad ? You would have to rewrite any section that uses inline data, when you changed Forths.  You can avoid this problem by using the INLINE words:  INLINE+ INLINE@ >INLINE and INLINE>  ( and adding them to other systems, as appropriate. ) you can write fully transportable inline code:    
  10587. : SLOW-LIT  ( --- N )  INLINE@ @ CELL INLINE+ ;  
  10588. This definition will work on ALL of the Forths I have over encountered, as long as you add the appropriate 4 inline definitions to the dictionary first.  by the way, SLOW-LIT is used as follows:  
  10589. : SLOW-LITERAL   ( N --- ) 
  10590.     COMPILE SLOW-LIT , ; IMMEDIATE 
  10591. : EXAMPLE  [ 5 ] SLOW-LITERAL ;  
  10592. You can always add these definitions to a system that doesn't have them. The definitions are very implementation dependent.  For an old fig Forth system they would be the simplest:  
  10593. : INLINE+  ( N --- )  ( ADDR --R-- ADDR+N )  
  10594.     COMPILE R> COMPILE + COMPILE >R ; IMMEDIATE 
  10595. : INLINE>  COMPILE R> ; IMMEDIATE 
  10596. : >INLINE  COMPILE >R ; IMMEDIATE 
  10597. : INLINE@  COMPILE R  ; IMMEDIATE 
  10598. In JForth the definitions are slightly more complicated, and on some of the 32 bit segment threaded Forths, they are fairly ugly. But once written, all the rest of your code flies!  
  10599. You may be confused by a word in JForth, INLINE , which has little to do with the inline words above.  INLINE sets a flag in a words header, telling the compiler that this word must be compiled inline, it cannot be called ( for instance >R ) .   
  10600. Don't Use JForth Internal Words   
  10601. Avoid using JForth internal words unless you can reconstruct them from scratch.    
  10602. Understand Unique Features Before Using Them  
  10603. Unfortunately, you also have to avoid using some of the nice JForth utilities unless you can reconstruct them as well.  At least we will keep the JForth utilities around.  All of the JForth unique programs are copyrighted, but many are available for distribution without charge.  If the file does not specifically state, that it may be freely distributed, than you must get our permission to distribute it elsewhere.  We encourage you to take the CELL and INLINE concepts and programs anywhere you want. Many of the JForth utilities are available on other Forths as well, and we made every attempt at compatibility with other Forths where this is appropriate. Some programs that you need permission to distribute are: ODE ASM DISM MULTISTANDARD LOCALS   
  10604. Delta Research is actively helping to establish better standards, particularly for high-end Forth systems.   
  10605. Conditional Compilation.      
  10606. Use the conditional compilation words, .IF .ELSE .THEN .NEED INCLUDE? , to adapt to different systems automatically.  Usually the differences between systems are small enough to allow one source to deal with all target systems.  Major sections that are different between targets, can be put into separate files, and conditionally loaded with INCLUDE? .  Unfortunately, The Forth community has not standardized the names for the conditional compilation words.  JForth uses the same names as LMI Forth. ( The '83 standard include a SUGESTED set of names that we think are unacceptable: IFTRUE OTHERWISE IFEND ).  The words we have used are easy to remember, since they work like the  familiar IF ELSE THEN  words all Forth programmers know so well.  The "." sets them apart from the ordinary conditionals as well.  We would have preferred [IF] [ELSE] [THEN] to emphasize the fact that these words work in a different state, but we felt it was better to use an existing acceptable set of words.
  10607. Multistandards
  10608. If you need to compile code that conforms to the FIG, Forth'79, or Forth'83 standard, then INCLUDE the file JU:MULTISTANDARDS.
  10609.  
  10610.  
  10611. Apendix F
  10612. Words by Function     
  10613. Address Conversion      
  10614. >ABS >REL IF>ABS IF>REL CALL>ABS 
  10615. AMIGA Library Access     
  10616. ARGS CALL CALL>ABS CALLVOID CALLVOID>ABS CLOSEALLLIBS CLOSELIB DCALL LIB? LIBRARY LIBVERSION OPENLIB  
  10617. Arithmetic       
  10618. * */ */MOD + +! +- - / /MOD 1+ 1- 2* 2+ 2- 2/ 4* 4+ 4- 4/ << @BITS ABS ASHIFT BIT-SET? BYTE-SWAP CLR-BIT COMP D+ D- D2* D2/ DABS DNEGATE DU2* DU2/ EVEN-UP FIG-NOT M* M/ M/MOD MAX MIN MOD NEGATE SQRT U* U/ U2* U2/ W/  
  10619. Conditional Compiling      
  10620. .ELSE .IF .NEED .THEN EXISTS? INCLUDE?  
  10621. Conditional Operators      
  10622. 0< 0= 0> < <= = > >= D< D= DU< FALSE NOT TRUE U< U> WITHIN?  
  10623. 'C' Structures from JU:CSTRUCT    
  10624. ..! ..@ :STRUCT ;STRUCT APTR ARRAYOF BYTE BYTES DST GETMODULE LONG OB.STATS? S@ S! SHORT SIZEOF() STRUCT UBYTE ULONG UNION{ USHORT }UNION }UNION{  
  10625. Compiler Support      
  10626. !CSP >INLINE >PARENT ?COMP ?CSP ?EXEC ?PAIRS BOTH BSR-CODE CALLADR, CARRAY CFA, COMPILE COMPILING? CREATECHAR DLIT DLITERAL DO-DOES-SIZE DOES> IMMEDIATE INLINE INLINEOK? INTERPRETING? JSR-CODE LIT LITERAL LONGCFA, RECOGNIZE RTS-CODE SMUDGE STATE UNSMUDGE [ [COMPILE] ]  
  10627. Debugging Aids      
  10628. &CHARS .FROM .FROM-OR.  .VOC 1010-EMULATE 1111-EMULATE }DEBUG BEST-GUESS DEBUG DEBUG{ DEBUG.ON DEF DO-TRACE DST DUMP FILE? FIND-DATA FIND-WDATA FREE-TRAP FROM-ADR FROM-VOC FROM-WORD GET-TCB GET-TRAP H.  IF-DEBUG IF-TESTING MAP MEMCELLS? NO-EMULATION NOTRAPS STACK-HOLD STACK.CHECK STACK.MARK START.UNRAVEL.QUIT STOP.UNRAVEL.QUIT SYSUSER# TIB.DUMP TRAPS UNRAVEL VALID-NAME? WORD.DUMP  
  10629. Dictionary Address Conversion     
  10630. '>BODY '>NAME >BODY >LINK >NAME BODY> LINK> N>LINK NAME>  
  10631. Dictionary Management      
  10632. ' , ALIGN ALLOT C, CRID.  DP DPLIMIT HERE ID.  IMMEDIATE? INITVOCS MAX-INLINE PAD ROMABLE ROOT W, [']  
  10633. DOS Commands from JU:DOSCOMMANDS    
  10634. +DOS >DOS ASSIGN AVAIL CD COPY DATE DELETE DIR DOS DOS0 DOSCOMMAND DOSSTRING INFO LIST NEWCLI PATH RENAME RUN STATUS  
  10635. Disassembler from JU:DISM     
  10636. ADISM DEF DISM DISM-CYCLES DISM-NAMES DISM-WORD? INIT-DISM RISM SELECT-DISM-DEFAULTS SEE  
  10637. Defining Words      
  10638. #VOCS : :CREATE ; ARRAY CONSTANT CREATE REVERTVOC USER VARIABLE VALUE { }  
  10639. Error Reporting      
  10640. .ERR ?ABORT" ?ERROR ABORT ABORT" ERROR MSG QUIT WARNING WARNING"  
  10641. Forth Screen Support     
  10642. BLK BLKERR LIST LOAD R# SCRED  
  10643. Flow of Control     
  10644. +LOOP -DO -LOOP 0BRANCH ?EXIT ?LEAVE ?RETURN ?STAY AGAIN BACK BEGIN BRANCH CASE CASE_FLAG CONDITION DO DO-LOOP-NEST ELSE END END-SELECT ENDCASE ENDCOND ENDOF EXIT FORWARD I IF IF-NOT IK J LEAVE LOOP LOOP-BACK LOOP-FORWARD NOT0BRANCH OF REPEAT RETURN SELECT THEN TIMES UNTIL UNTIL-NOT WHILE WHILE-NOT  
  10645. FILE I/O      
  10646. $FOPEN +DOS @&CLOSEFILES ACCESS_READ ACCESS_WRITE BLOCK CLOSEFILES EOF EOL F@, F@,? FCLOSE FCLOSEATBYE FCLOSEVAR FEMIT FERROR FILEMODE FKEY FDUMP FOPEN FREAD FREAD? FSEEK FSEEK? FTYPE FWRITE MARKFCLOSE MODE_NEWFILE MODE_OLDFILE NEW OFFSET_BEGINNING OFFSET_CURRENT OFFSET_END OLD TEMPBUFF TEMPF, TEMPFILE TYPEFILE UNMARKFCLOSE  
  10647. Floating Point      
  10648. F.  F* FLOAT FNUMBER FNUMBER? FSIN see chapter on Floating Point  
  10649. Forth System      
  10650. BYE COLD INTERPRET QUIT  
  10651. Host Portability      
  10652. 'C CELL CELL* CELL+ CELL- CELL/ CELLS CFA->PFA HO.FIND.CFA HO.FIND.PFA HOST" HO_MAX_INT HO_MIN_INT INLINE+ INLINE> INLINE@ PFA->NFA PICK79 PICK83 REL->USE USE->REL  
  10653. INPUT       
  10654. #TIB >IN ?PAUSE ?TERMINAL BSIN EXPECT FILEWORD HISTORY KEY PARSE PARSE-WORD QUERY SKIP-WORD? SOURCE SPAN TIB TIB0 TIBEND UNWORD WORD Y/N  
  10655. I/O  General     
  10656. #CHARS ?LETTER ?VISIBLE ASCII BL CONSOLE EMPTYCHAR HICASE LINELIMIT LOCASE LPLACE LWORD NOCASE OFFSET PLACE  
  10657. Logging to a File from JU:LOGTO  
  10658. $LOGTO LOGEND LOGGED? LOGSTART LOGSTOP LOGTO  
  10659. Logical       
  10660. !BITS +SHIFT -SHIFT AND OR SET-BIT SHIFT WORD-SWAP XOR |  
  10661. Memory Access      
  10662. ! +! -> 2! 2@ ? @ ABS! ABS@ ABSC! ABSC@ ABSW! ABSW@ C! C@ CMOVE CMOVE> D! D@ ERASE FILL MOVE ODD! ODD@ ODDD! ODDD@ ODDW! OFF ON SPARE TOGGLE W! W@ WMOVE X! X@  
  10663. Memory Allocation      
  10664. +STACK -STACK @&FREEBLOCKS ALLOCBLOCK ALLOCBLOCK? ALLOCSTRUCT FREEATBYE FREEBLOCK FREEBLOCKS FREEBYTE FREEBYTEA FREECELL FREEMEM MARKFREEBLOCK MEMF_CHIP MEMF_CLEAR MEMF_FAST MEMF_LARGEST MEMF_PUBLIC NEXTMEM NEXTMEMA POP PUSH SIZEMEM UNMARKFREEBLOCK XALLOCBLK XFREEBLK  
  10665. Numeric Conversion      
  10666. # #> #DIGS #DIGITS #S $ (NUMBER) .  .HEX .HX .R <# BASE BINARY COMMAS CONVERT D.  D.R DECIMAL DIGIT DIGS/, DPL HEX HLD HOLD N>TEXT NO-COMMAS NUMBER NUMBER? SIGN U.   
  10667. Output       
  10668. +OUT ." .S <FASTEMIT> <FASTKEY> <FLUSHEMIT> >NEWLINE ?MORE ?WRAP BELL BSOUT CLRCHAR CLS CR CR? EMIT EMIT-TO-COLUMN FAST FLUSHEMIT MAX-TYPE OUT OUTBUF OUTPUT-CASE SLOW SPACE SPACES TAB TAB-WIDTH TYPE TYPE-HERE WTYPE  
  10669. Random Numbers from JU:RANDOM    
  10670. CHOOSE RAND-SEED RANDOM WCHOOSE  
  10671. Return Stack      
  10672. .RS .RSTACK 0RP >R DUP>R MYRP R R0 R> R@ RDEPTH RDROP RP! RP@ RP+! RPICK SET-RP X>R XR> XRDROP  
  10673. Saving and Loading     
  10674. #K #RELOCS #U .IMAGE .RELOCS ?FORGOTTEN ABSRELOCS CLONE FBLK FILEHEADERS HEADTAIL IFOPTIMIZE INCLUDE INCLUDE? LOAD-FILE PUSHRELOC REDEF? RELOCSADR SAVE-FORTH SAVE-IMAGE SCR-FILE SCREDING TURNKEY TURNKEYING?  
  10675. Stack Manipulation      
  10676. -2SORT -DUP -ROT 0SP 2DROP 2DUP 2OVER 2SORT 2SWAP ?DUP ?STACK CSP DDROP DDUP DEPTH DROP DSWAP DUP MYDSP MYTOS NIP OVER PICK ROT S0 SET-SP SP! SP@ SWAP TUCK XDROP XDUP XPICK  
  10677. Strings       
  10678. " $" $, $- $.  $= $ACCUM $APPEND $CLR $CONCAT $LEN $MOVE $N>S $SIZE $TYPE $VARIABLE -TRAILING /STRING 0" COMPARE COUNT MAKEUCASE MATCH? MCASE-SENSITIVE SCAN SKIP SKIP-WORD SKIPWORD TEXT=? UPPER UPPERC@  
  10679. Timers       
  10680. BENCH BENCH.WITH MEASURE MSEC PROFILE
  10681. Unused Words Analysis from JU:UNUSED   
  10682. CLEAR.MARKS MARK.UNUSED MARK.USED START.MARKING.WORDS STOP.MARKING.WORDS UNUSED.WORDS USED.WORDS USED_BIT  
  10683. User Stack      
  10684. >US 'USP> INIT-USP US-DEPTH US-PICK US> US@ USP! USP@ UP0 USP  
  10685. Vectored Execution      
  10686. >IS @EXECUTE COLDEXEC DEFER DEFER-EXECUTE EXECUTE GLOBAL-DEFER IS ISDEFUSER? WHAT'S  
  10687. Virtual File I/O     
  10688. BUFFERADR CLOSEFVREAD CLOSEFVWRITE F, FFLUSH? LINESFILLV OPENFV READLINE VIRTBUFFSIZE  
  10689. Vocabulary Management      
  10690. ANEW CONTEXT CURRENT FENCE FIND FORGET FREEZE LATEST MAXVOCS SCAN-ALL-VOCS SCAN-VOC SCAN-WORDS VALLOT VLATEST>VLINK VLINK>' VLINK>VLATEST VLIST VOC-LINK VOCABULARY WHEN-SCANNED WHEN-VOC-SCANNED WORDS WORDS-LIKE  
  10691. Word Sizing      
  10692. B->S S->D W->S  
  10693.  
  10694.  
  10695. Appendix G
  10696. Incompatibilities   
  10697. Between V2.0 and V3.0
  10698. Error Handling in IFF and Picture words.
  10699. Numerous changes have been made in the way that these words handle errors.  IFF.WRITE? has a new stack diagram.  These changes are described in detail in a special section on incompatibilities in chapter 21.
  10700. Local Variables
  10701. The local variable used in V2.0 have been completely replaced.  We tried to make the new ones compatible with the old ones but there are some differences.  The new locals are kept on the return stack instead of the data stack.  The only code that should be affected was code that illegally used internal aspects of the old locals or that illegally relied on the parameters being on the data stack.
  10702. Between V1.2 and V2.0   
  10703. The changes between JForth 1.2 and 2.0 mainly involve the addition of new code.  We tried to avoid making any changes that would cause  code written using version 1.2 to fail under 2.0.  In some cases, however, we felt that the definition of a word in 1.2 was faulty and was worth correcting. Luckily the changes are minor.   
  10704. >BODY and BODY>     
  10705. In JForth 1.2, these were defined as NOOP.  This was because JForth is subroutine threaded does not have a traditional CFA and PFA.  We felt, however, that >BODY was mainly used to get the address of data in a CREATE DOES> word.  For JForth, this meant we had to change the definition from NOOP to:  
  10706. : >BODY  ( cfa -- body ) DO-DOES-SIZE + ; 
  10707. Please correct for this in your code if you use >BODY or BODY>.   
  10708. CONSOLE       
  10709. This variable contained the address of the file used for I/O by JForth V1.2.  Since I/O is a two way street, Input AND Output, we actually need two separate variables.  This is required to make I/O redirection work properly in Cloned programs.  We, therefore, split CONSOLE into CONSOLEIN and CONSOLEOUT.  The single word CONSOLE! was added that will set both of these variables.  We also added CONSOLE@ for symmetry.  CONSOLE@ fetches the value of CONSOLEOUT.   
  10710. In JForth V1.2:  
  10711. CONSOLE   ! 
  10712. In JForth V2.0:  
  10713. CONSOLE!  ( one word ) 
  10714. Totally New Floating Point    
  10715. The old floating point system was not worth keeping after we got a better version from Dave Sirag.  We recommend that you switch to this new system. If you absolutely need the old system, take it off of the old disks.   
  10716. Bugs Fixed  
  10717. Since bugs were fixed in these words, they will behave differently.  You will only have to change your code if you had made a patch for these words.   There were other bugs fixed but they should not affect stack diagrams.
  10718. ROLL  ( was totally messed up, now OK )
  10719. U/    ( gave wrong answers sometimes for big numbers )
  10720. D!    ( used to swap halves incorrectly, not anymore )  
  10721. Signed AND Unsigned Structure Members
  10722. JForth 1.2 treated all structure members as unsigned.  The Amiga makes a distinction between signed and unsigned so JForth 2.0 does so as well.  The difference is that if you FETCH an 8 or 16 bit signed member, it will be sign extended if it is declared as SHORT or BYTE.  Members declared as USHORT or UBYTE will not be sign extended.  If you store a -3 in a signed BYTE using ..! then get it back using ..! , you will have -3 on the stack.  In an UNSIGNED BYTE you would end up with hex FD.
  10723. We have given you an option here.  If you do not want automatic sign extension in your program, compile your code with the variable SIGNED-MEMBERS set to FALSE.  The default is TRUE.
  10724.  
  10725. Appendix G
  10726. Incompatibilities   
  10727. Between V2.0 and V3.0
  10728. Error Handling in IFF and Picture words.
  10729. Numerous changes have been made in the way that these words handle errors.  IFF.WRITE? has a new stack diagram.  These changes are described in detail in a special section on incompatibilities in chapter 21.
  10730. Local Variables
  10731. The local variable used in V2.0 have been completely replaced.  We tried to make the new ones compatible with the old ones but there are some differences.  The new locals are kept on the return stack instead of the data stack.  The only code that should be affected was code that illegally used internal aspects of the old locals or that illegally relied on the parameters being on the data stack.
  10732. Between V1.2 and V2.0   
  10733. The changes between JForth 1.2 and 2.0 mainly involve the addition of new code.  We tried to avoid making any changes that would cause  code written using version 1.2 to fail under 2.0.  In some cases, however, we felt that the definition of a word in 1.2 was faulty and was worth correcting. Luckily the changes are minor.   
  10734. >BODY and BODY>     
  10735. In JForth 1.2, these were defined as NOOP.  This was because JForth is subroutine threaded does not have a traditional CFA and PFA.  We felt, however, that >BODY was mainly used to get the address of data in a CREATE DOES> word.  For JForth, this meant we had to change the definition from NOOP to:  
  10736. : >BODY  ( cfa -- body ) DO-DOES-SIZE + ; 
  10737. Please correct for this in your code if you use >BODY or BODY>.   
  10738. CONSOLE       
  10739. This variable contained the address of the file used for I/O by JForth V1.2.  Since I/O is a two way street, Input AND Output, we actually need two separate variables.  This is required to make I/O redirection work properly in Cloned programs.  We, therefore, split CONSOLE into CONSOLEIN and CONSOLEOUT.  The single word CONSOLE! was added that will set both of these variables.  We also added CONSOLE@ for symmetry.  CONSOLE@ fetches the value of CONSOLEOUT.   
  10740. In JForth V1.2:  
  10741. CONSOLE   ! 
  10742. In JForth V2.0:  
  10743. CONSOLE!  ( one word ) 
  10744. Totally New Floating Point    
  10745. The old floating point system was not worth keeping after we got a better version from Dave Sirag.  We recommend that you switch to this new system. If you absolutely need the old system, take it off of the old disks.   
  10746. Bugs Fixed  
  10747. Since bugs were fixed in these words, they will behave differently.  You will only have to change your code if you had made a patch for these words.   There were other bugs fixed but they should not affect stack diagrams.
  10748. ROLL  ( was totally messed up, now OK )
  10749. U/    ( gave wrong answers sometimes for big numbers )
  10750. D!    ( used to swap halves incorrectly, not anymore )  
  10751. Signed AND Unsigned Structure Members
  10752. JForth 1.2 treated all structure members as unsigned.  The Amiga makes a distinction between signed and unsigned so JForth 2.0 does so as well.  The difference is that if you FETCH an 8 or 16 bit signed member, it will be sign extended if it is declared as SHORT or BYTE.  Members declared as USHORT or UBYTE will not be sign extended.  If you store a -3 in a signed BYTE using ..! then get it back using ..! , you will have -3 on the stack.  In an UNSIGNED BYTE you would end up with hex FD.
  10753. We have given you an option here.  If you do not want automatic sign extension in your program, compile your code with the variable SIGNED-MEMBERS set to FALSE.  The default is TRUE.
  10754.  
  10755.  
  10756. Appendix H
  10757. Products Written in JForth
  10758. This chapter describes commercial products that have been written in JForth.  This is a partial list and contains only the ones we know about.  If you have any JForth programs that you are selling, send us information and hopefully a sample copy, and we will, if possible, include a description for free in our next manual.  If you read about something here that you like, please help your fellow JForth programmers by buying it.  
  10759. B.A.D. from MV Micros
  10760. This "best selling utility" optimizes disk access time up to 500% by analyzing and restructuring any Amiga DOS disk.  B.A.D. can reduce "disk gronking", speedup window opening under Workbench, and speed up DIR and other disk operations.  B.A.D. also includes a disk structure test to detect errors.  Works on both floppy and hard disks.  B.A.D. is available from many mail order outlets.  It is distributed by Centaur Software, Inc.
  10761. My Diary from MV Micros
  10762. My Diary is a full featured Personal Information Manager (PIM).  My Diary provides a pop-up notepad for managing names, phone numbers, addresses, appointments, "to do" lists, due dates, diaries, birthdays, etc.  Notes are date stamped and can be attached to the calendar.  Notes can be searched for keywords.  Timers can be used to provide reminders.  Information can be imported from and exported to hand held electronic organizers like the Sharp Wizard.  ARexx support and Auto Dialer also provided.
  10763. HMSL, the Hierarchical Music Specification Language
  10764. HMSL is a programming language for experimental music composition and performance.  It is an extension to JForth that adds MIDI capability, local sound support, and an extensive set of object-oriented ODE classes for organizing, manipulating and playing musical data.  HMSL also includes a graphics toolbox for building interactive screens, a score entry dialect, and a simple sequencer.  HMSL was developed by Phil Burk, Larry Polansky, and David Rosenboom.  For information contact:
  10765. Frog Peak Music
  10766. P.O. Box 151051
  10767. San Rafael, CA
  10768. 94915-1051
  10769. (415) 461-1442
  10770. Copyist Companion by Nick Didkovsky
  10771. Copyist Companion converts Deluxe Music Construction Set (DMCS) score  files to Dr. T's The Copyist files.  All the features of the DMCS  score are meticulously converted, including time and key signature  changes, clefs, ties, beaming, stem direction, slurs, dots, chords,  triplets, quintuplets, accidentals, dynamics, etc.  The result is a  beautifully laid out Copyist score, ready for professional printing. Copyist Companion was written in JForth (of course) and runs on any Amiga. The great quantity of reverse engineering required to parse the DMCS  file format made JForth and ODE the only programming environment I would have considered using for this project. You can get more info about Copyist Companion from: 
  10772. Nick Didkovsky
  10773. 171 East 99th Street #20
  10774. New York, NY 10029
  10775. (212) 369-1733
  10776. email didkovsk@dorsai.com
  10777. Or contact Dr. T's Music Software, who are distributing Copyist Companion. 
  10778. Nick is also developing a DMCS to MIDIfile conversion utility.  Call or write for details on its progress. 
  10779.  
  10780. Doctor Nerve with Nick Didkovsky
  10781. Doctor Nerve's latest two CD's are "Beta 14 ok" and "Did Sprinting Die?".  Both projects include compositions generated by HMSL (thus the JForth connection).  These compositions are performed by the band on "Beta" and directly by Amiga/HMSL on "Sprinting". Both CD's also include non-HMSL-composed material.  See if you can tell the  difference!
  10782. Doctor Nerve LP's and CD's can be ordered from:
  10783. Wayside Music
  10784. PO Box 6517
  10785. Wheaton, MD 20906.
  10786. Ask for their catalog.  Or contact Nick Didkovsky as above.
  10787. IntuiEZ by Curtis Stanton
  10788. IntuiEZ is a shareware program that allows the user to interactively design screens and windows with gadgets using the mouse.  You can then output JForth compatible source code to a file.  IntuEZ also has the ability to capture the Intuition structure from other applications screens and window for study or modification.  This can create gadgets with the version 2.0 style 3D gadgets but it.works with Amiga DOS 1.3.  At press time it was not known how this program would be distributed so call Delta Research for the latest information, or look for it on a BBS.
  10789. XL by Martin Kees
  10790. XL is a cel animation program by the author of JForth's ANIM support routines.  It uses an onion-skin display that lets you see several cels at once.  It also features a very powerful bezier curve editor.  A demonstration version of XL can be found on Fred Fish disk #516 which, by the way, is entirely filled with programs written in JForth.  On the same disk check out Enigma, a beautiful puzzle that models a programmable machine.
  10791. JGoodies_1 from various.
  10792. Check out Fred Fish disk #239.  It is also all JForth code.  Includes a fast Mandelbrot generator, audio tools, FFT code, HeadClean, and other goodies.
  10793. AP -      Appendices
  10794.  
  10795.     Appendices    AP -  
  10796.  
  10797.  
  10798.  
  10799.  
  10800.  
  10801.  
  10802.